小阶段总结
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
</svg>
<blockquote>
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
javaweb & spring5 & springMVC & MyBatis
- 阶段复习
- 一、Javaweb阶段
- 二、spring5
- 三、 springMVC
- 四 、MyBatis
- 总结
阶段复习
针对之前学习的javaweb及SSM框架进行复习。
提示:以下是本篇文章正文内容,下面案例可供参考
一、Javaweb阶段
1.水果库存版本迭代
fruit1.0 - jdbc
fruit1.1 - jdbc
fruit1.2 - jdbc
fruit1.3 - jdbc
从fruit1.0开始引入数据库jdbc:连接数据库jdbc
fruit 1.4 thymeleaf
fruit 1.5 thymeleaf
fruit 1.4 开始拥有界面,1.4之前是控制台显示效果 ,然后一步步追加功能
fruit 1.6 pagination 分页 功能添加
fruit 1.7 keyword 根据关键词查询
从fruit 1.8 开始,对系统结构进行思考,构思。1.8之前是完善功能。
fruit 1.8 mvc 对servlet进行改造,使用Switch-case将多个servlet优化为一个servlet(FruitServlet),因为发现当业务繁琐时,会出现繁冗的Switch-case
fruit 1.9 mvc -refleat 利用反射对Switch-case进行优化(判断operate)
fruit 2.0 mvc-dispatcherServlet 当有很多像FruitServlet(UserServlet…)这样的操作实体对象后,反射代码又会重复写一遍,将反射代码继续向上提取,得到dispatcherServlet:核心控制器/中央控制器
fruit 2.1 mvc-controller
将之前的servlet变成一个一个普通的controller(一般情况下,controller会分为3个部分:第一个部分:获取参数;第二个部分:业务处理;第三个部分:视图资源的转发或重定向),继而发现,请求参数和视图处理在每个controller中都有,进而将获取参数和视图处理抽取到dispatcherServlet里面,因此dispatcherServlet是完成一些通用的功能,让controller能够更专注的进行业务的处理,所以controller慢慢的变成一个普通的类,不在和servletAPI进行耦合了,好处是:能够很方便的对controller里面的每个方法进行单元测试。当然,controller并没有完全和servletAPI 0耦合,因为有时会用到session
fruit 2.2 mvc- service -ioc
因为DAO中全都是单精度的方法,一个业务最后会有多个DAO这样的单精度方法组成,所以需要业务层。不需要把业务操作的步骤散在控制器controller中,否则控制器中需要考虑第一步调用谁、第二步调用谁、…这样的话controller负担会比较重。而controller是面向业务的,所以我们将各个步骤封装到service中,让控制器直接调用业务组件中的业务方法。当引入service后,发现层与层之间是有耦合的,所以需要降低耦合,进而引入IOC容器。层与层之间组件的依赖关系通过IOC来帮我们注入,称为依赖注入。之前的这些对象是程序员自己创建的,意味着其生命周期是由我们来控制的;现在我们将这些对象的创建和销毁放到IOC容器中,让IOC容器帮我们进行管理他们的生命周期,称为控制反转。这些对象的控制权从程序员转换到IOC容器。
fruit 2.3 mvc-transaction
servlet这个API,里面具体讲了其初始化方法init(), 这个方法有一个参数servletConfig 。 还有一个接口叫
ServletContext(上下文),通过这个上下文对象获取上下文参数,上下文的参数可以在web.xml中进行配置(context-param)。
监听器及过滤器******
事务管理:①设置不自动提交:set AutoCommit(false);②提交:commit;③回滚:rollback。当正常的时候,进行commit,当有异常的时候,进行rollback。但是这个事务的操作是基于connection的API,但是事务应该处于业务层,不应该处于DAO层(DAO中都是单精度的方法),因为我们需要保证一个业务功能的成功或失败,一个业务功能的成功需要保证它里面的多个单精度的DAO方法都成功,这个业务方法失败应该是多个DAO方法都失败,不能部分成功,部分失败。那么此时的难点就是conn对象,因为DAO方法中conn对象都是特有的,是不共享的,在事务中我们需要这些方法都**共享一个conn对象**********进而引入threadlocal。进而将事务的操作抽取成一个TransactionManager类,其内提供三个简单的方法:开启事务beginTrans ; 提交事务commit ; 回滚事务 rollback 。 在这个类中将繁琐的代码抽取成一个ConnUtil类,在这个类中设定了两个方法:getConn:从threadLocal中获取(get(),如果没有,则创建一个,用完之后再放到纽带上去) ; closeConn 方法(从threadLocal中获取conn,如果不为空,则将conn关闭,并且将threadLocal设置为null)。
进而讲了threadlocal中的实现原理:set() , get():如何确认当前线程和其他线程不会混淆,因为获取的是当前线程,作为一个key,然后调用threadlocal中的getMap()方法,所以线程不同,获取到的threadlocalMap就不同,进而获取到的内容就不一样了。threadlocal可以创建多个,比如threadlocal1,threadlocal2,threadlocal3…那key不一样,获得的value(entry)就不一样。
OpenSessionInViewFilter这个过滤器,这个过滤器开始工作的时候,我们就开启事务,然后doFilter放行,进行后面的业务操作,操作完只要没有错误,我们就正常的commit,一旦有问题,我们就catch到,然后rollback。为了确认当真的发生问题的时候,确认是否真的回滚,(内部已经try-catch了,因此问题不会暴露出来,因此在OpenSessionInViewFilter永远也不会捕获到异常,即catch住),所以我们把每一层上面的异常都进行封装,封装对外抛出运行时异常,进而在过滤器中就可以捕获到了。
2. 图解:mvc各个层之间的设计
客户端发送一个请求给服务器,然后服务器端有两个filter,第一个filter:CharterEncodingFilter,用来进行设置编码,放行;然后有一个OpenSessionInViewFliter;这个过滤器放行之后,会经过一个中央控制器DispatchServlet,会去解析URL ,得到一个path(fruit)并且会得到operate,根据这个fruit然后会去找到Fruitcontroller,根据operate的值找到其中的方法,在这个方法内部会去调用FruitService中的方法,FruitService又去调用FruitDAO中的方法,而FruitDAO的父类其实是BaseDAO,BaseDAO会帮我们访问数据库。DispatchServlet这个控制器中做了三件事:①参数处理;②通过反射中的invoke方法,调用controller内部的方法;③视图处理。
IOC容器中配置有很多组件,
<bean id="fruit">
<property fruitService>
<bean id="fruitService">
<property fruitDAO>
<bean id=" fruitDAO">
这三个组件对应三个key,通过解析URL得到的fruit就会和IOC container中的fruit对应,然后IOC 中id=fruit就能对应到Fruitcontroller(因为id后面配的class就是Fruitcontroller),通过operate = index这个反射技术找到Fruitcontroller中的index方法,在Fruitcontroller中有一个FruitcontService属性(private FruitService fruitService = null),这说明Fruitcontroller和FruitService之间有依赖,通过IOC中的property属性中的ref注入给Fruitcontroller中的fruitService,知道这个对象之后就能给它注入值,称为依赖注入。同样的道理,FruitService中也需要FruitDAO。
在BaseDAO中有四个方法,
executeUpdate(sql,params) ;
executeQuery(sql,params);
load(sql,params);
executeComplexQuery(sql,params)
关于事务的管理,在OpenSessionInViewFliter当中:
try{开启事务,
放行,
提交}
catch(){
回滚}
在FruitService中存在一个service调用多个DAO,比如在FruitDAO中有多个方法,当我们想要共享一个Conn时,因为这些方法和线程有关(threadlocal),当我们需要数据时,就可以在threadlocal中获取
二、spring5
spring框架概述
Spring是轻量级的开源的JavaEE框架
spring有两个核心:IOC和AOP
(1)IOC:控制反转,把创建对象过程交给Spring进行管理
(2)Aop:面向切面,不修改源代码进行功能增强
IOC容器
1 IOC底层原理
(1) 什么是IOC(Inversion of Control)
(1)控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理
(2)使用IOC目的:为了耦合度降低
(2) 底层原理
(1)xml解析、工厂模式、反射
2 IOC接口(BeanFactory)
1、IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
2、Spring提供IOC容器实现两种方式:(两个接口)
(1)BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用
加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象 -----在用的时候才创建对象
(2)ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用
加载配置文件时候就会把在配置文件对象进行创建 ------ 在一开始加载配置文件的时候就创建了对象
3 IOC操作Bean管理(基于xml)
1、什么是Bean管理
(0)Bean管理指的是两个操作
(1)Spring创建对象
(2)Spirng注入属性
1、基于xml方式创建对象
(1)在spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建
(2)在bean标签有很多属性,介绍常用的属性
id属性:唯一标识
class属性:类全路径(包类路径)
(3)创建对象时候,默认也是执行无参数构造方法完成对象创建
遇到如下问题:
报错:
Caused by: java.lang.NoSuchMethodException: com.atguigu.spring5.User.<init>()
没有无参构造器
2、基于xml方式注入属性
(1)DI:依赖注入,就是注入属性
2.1、第一种注入方式:使用set方法进行注入
(1)创建类,定义属性和对应的set方法
//演示属性注入之set方法
//创建属性
private String bname;
private String bauthor;
private String address;
//创建属性对应的set()方法
public void setBname(String bname) {
this.bname = bname;
}
public void setBauthor(String bauthor) {
this.bauthor = bauthor;
}
public void setAddress(String address) {
this.address = address;
}
public void testDemo(){
System.out.println(bname + "::" +bauthor +"::" + address);
}
}
(2)在spring配置文件配置对象创建,配置属性注入
<!-- 1 配置User对象创建--> <!--<bean id="user" class="com.atguigu.spring5.User"></bean>-->
<span class="token comment"><!--2 set方法注入属性 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>bean</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>book<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.atguigu.spring5.Book<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token comment"><!--使用porperty完成属性注入 name:类里面属性名称 value:向属性注入的值 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>bname<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>易筋经<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>property</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>bauthor<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>达摩老祖<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>property</span><span class="token punctuation">></span></span> <span class="token comment"><!-- 给属性注入null值 --></span> <span class="token comment"><!--<property name="address">--></span> <span class="token comment"><!--<null/>--></span> <span class="token comment"><!--</property>--></span> <span class="token comment"><!-- 属性值包含特殊符号 例如:address <<南京>> 1 把<>进行转义 &lt ; &gt : 小于和大于号 2 把带特殊符号内容写到CDATA :先写<> 再写! 然后写[[]]:两个[],在第一个[]里面写CDATA ; 在第二个[]里面写具体内容 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>address<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>value</span><span class="token punctuation">></span></span><span class="token cdata"><![CDATA[<<南京>>]]></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>value</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>property</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>bean</span><span class="token punctuation">></span></span>
2.2 第二种注入方式:使用有参数构造进行注入
(1)创建类,定义属性,创建属性对应有参数构造方法
/**演示有参构造注入属性 */ public class Orders { private String oname; private String address;
<span class="token keyword">public</span> <span class="token class-name">Orders</span><span class="token punctuation">(</span><span class="token class-name">String</span> oname<span class="token punctuation">,</span> <span class="token class-name">String</span> address<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>oname <span class="token operator">=</span> oname<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>address <span class="token operator">=</span> address<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testOrders</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>oname <span class="token operator">+</span> <span class="token string">"::"</span> <span class="token operator">+</span> address<span class="token punctuation">)</span><span class="token punctuation">;</span>
加粗样式 }
}
(2)在spring配置文件中进行配置
<!-- 有参构造注入属性 -->
<bean id="orders" class="com.atguigu.spring5.Orders">
<constructor-arg name="oname" value="电脑"></constructor-arg>
<constructor-arg name="address" value="China"></constructor-arg>
</bean>
2.5、p名称空间注入(了解)
(1)使用p名称空间注入,可以简化基于xml配置方式
第一步 添加p名称空间在配置文件中
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
第二步 进行属性注入,在bean标签里面进行操作
p名称空间 对set方法注入属性的简化 了解即可
<bean id="book" class="com.atguigu.spring5.Book" p:bname="九阳神功" p:bauthor="无名氏"></bean>
3.1 IOC操作 Bean 管理( xml 注入其他类型属性)
1.字面量
<!-- 给属性注入null值 --> <property name="address"> <null/> </property>
<span class="token comment"><!-- 属性值包含特殊符号 例如:address <<南京>> 1 把<>进行转义 &lt ; &gt : 小于和大于号 2 把带特殊符号内容写到CDATA :先写<> 再写! 然后写[[]]:两个[],在第一个[]里面写CDATA ;在第二个[]里面写具体内容 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>address<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>value</span><span class="token punctuation">></span></span><span class="token cdata"><![CDATA[<<南京>>]]></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>value</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>property</span><span class="token punctuation">></span></span>
2、注入属性-外部bean
(1)创建两个类 service类和dao类
(2)在service调用dao里面的方法
(3)在spring配置文件中进行配置
public class UserService {
<span class="token comment">//创建UserDAO类型属性,生成set()方法</span> <span class="token keyword">private</span> <span class="token class-name">UserDAO</span> userDAO<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setUserDAO</span><span class="token punctuation">(</span><span class="token class-name">UserDAO</span> userDAO<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>userDAO <span class="token operator">=</span> userDAO<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">add</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"service add......."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> userDAO<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
public interface UserDAO {
public void update();
}
public class UserDAOImpl implements UserDAO{
@Override
public void update() {
System.out.println("dao update............");
}
}
bean.xml
<!--注入属性 外部bean-->
<!-- 1 service 和 dao 对象创建-->
<bean id="userService" class="com.atguigu.spring5.service.UserService">
<!--注入userDAO对象
name属性:类里面的属性名称(service类里面私有属性的名称)
ref属性:创建userDAO对象bean标签id值
注意:id 的名称是可以随便起的,我也可以起为userDAOImpl,ref 名称和注入对象的id要一致
-->
<property name="userDAO" ref="userDAO"></property>
</bean>
<bean id="userDAO" class="com.atguigu.spring5.dao.UserDAOImpl"></bean>
3、注入属性-内部bean
(1)一对多关系:部门和员工
一个部门有多个员工,一个员工属于一个部门
部门是一,员工是多
(2)在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示
public class Dept { private String dname;
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setDname</span><span class="token punctuation">(</span><span class="token class-name">String</span> dname<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>dname <span class="token operator">=</span> dname<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> <span class="token string">"Dept{"</span> <span class="token operator">+</span> <span class="token string">"dname='"</span> <span class="token operator">+</span> dname <span class="token operator">+</span> <span class="token char">'\''</span> <span class="token operator">+</span> <span class="token char">'}'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
public class Emp {
private String ename;
private String gender;
//员工属于某一个部门,使用对象形式表示
private Dept dept;
//生成getDept()方法(级联赋值第二种写法需要)
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public void setEname(String ename) {
this.ename = ename;
}
public void setGender(String gender) {
this.gender = gender;
}
public void add(){
System.out.println(ename + "::" + gender + "::" + dept);
}
}
(3)在spring配置文件中进行配置
<!--注入属性 内部bean--> <bean id="emp" class="com.atguigu.spring5.bean.Emp"> <!--设置两个普通属性--> <property name="ename" value="lina"></property> <property name="gender" value="女"></property> <!--设置对象类型属性--> <property name="dept"> <bean id="dept" class="com.atguigu.spring5.bean.Dept"> <property name="dname" value="安保部"></property> </bean>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>property</span><span class="token punctuation">></span></span>
</bean>
4、注入属性-级联赋值
(1)第一种写法
<!--注入属性 级联赋值-->
<bean id="emp" class="com.atguigu.spring5.bean.Emp">
<!--设置两个普通属性-->
<property name="ename" value="lina"></property>
<property name="gender" value="女"></property>
<!--级联赋值-->
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.atguigu.spring5.bean.Dept">
<property name="dname" value="财务部"></property>
</bean>
(2)第二种写法
<!--注入属性 级联赋值-->
<bean id="emp" class="com.atguigu.spring5.bean.Emp">
<!--设置两个普通属性-->
<property name="ename" value="lina"></property>
<property name="gender" value="女"></property>
<!--级联赋值-->
<property name="dept" ref="dept"></property>
<property name="dept.dname" value="技术部"></property>
</bean>
<bean id="dept" class="com.atguigu.spring5.bean.Dept">
<!-- <property name="dname" value="财务部"></property>-->
</bean>
IOC操作 Bean 管理( xml 注入集合属性)
1、注入数组类型属性
2、注入List集合类型属性
3、注入Map集合类型属性
4、注入set集合类型属性
(1)创建类,定义数组、list、map、set类型属性,生成对应set方法
public class Stu { //1.数组类型属性 private String[] courses; //2.List集合类型属性 private List<String> list; //3.Map集合类型属性 private Map<String, String> maps; //4.set集合类型属性 private Set<String> sets;
<span class="token comment">//5.学生所学多门课程</span> <span class="token keyword">private</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Course</span><span class="token punctuation">></span></span> courseList<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setCourseList</span><span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Course</span><span class="token punctuation">></span></span> courseList<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>courseList <span class="token operator">=</span> courseList<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setCourses</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> courses<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>courses <span class="token operator">=</span> courses<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setList</span><span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">></span></span> list<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>list <span class="token operator">=</span> list<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setMaps</span><span class="token punctuation">(</span><span class="token class-name">Map</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">></span></span> maps<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>maps <span class="token operator">=</span> maps<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setSets</span><span class="token punctuation">(</span><span class="token class-name">Set</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">></span></span> sets<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>sets <span class="token operator">=</span> sets<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">Arrays</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span>courses<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>list<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>maps<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>sets<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>courseList<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
(2)在spring配置文件进行配置
<!--集合类型注入-->
<bean id="stu" class="com.atguigu.spring5.collectiontype.Stu">
<!--数组类型属性注入-->
<property name="courses">
<array>
<value>java课程</value>
<value>数据库课程</value>
</array>
</property>
<!--list集合类型属性注入-->
<property name="list">
<list>
<value>张三</value>
<value>小三</value>
</list>
</property>
<!--Map集合类型属性注入-->
<property name="maps">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>
<!--set集合类型属性注入-->
<property name="sets">
<set>
<value>MySQL</value>
<value>Redis</value>
</set>
</property>
<!--注入list集合类型,值是对象-->
<property name="courseList">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
4、在集合里面设置对象类型值
public class Course { private String cname;//课程名称
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setCname</span><span class="token punctuation">(</span><span class="token class-name">String</span> cname<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>cname <span class="token operator">=</span> cname<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> <span class="token string">"Course{"</span> <span class="token operator">+</span> <span class="token string">"cname='"</span> <span class="token operator">+</span> cname <span class="token operator">+</span> <span class="token char">'\''</span> <span class="token operator">+</span> <span class="token char">'}'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
<!--创建多个course对象-->
<bean id="course1" class="com.atguigu.spring5.collectiontype.Course">
<property name="cname" value="Java课程"></property>
</bean>
<bean id="course2" class="com.atguigu.spring5.collectiontype.Course">
<property name="cname" value="MyBaits课程"></property>
</bean>
5、把集合注入部分提取出来
(1)在spring配置文件中引入名称空间 util
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
(2)使用util标签完成list集合注入提取
<!--1 提取list集合类型属性注入--> <util:list id="bookList"> <value>易筋经</value> <value>九阴真经</value> <value>九阳神功</value> </util:list>
<!--2 提取list集合类型属性注入使用-->
<bean id="book" class="com.atguigu.spring5.collectiontype.Book" scope="prototype">
<property name="list" ref="bookList"></property>
</bean>
3.2 IOC操作 Bean 管理( FactoryBean)
1、Spring有两种类型bean,一种普通bean,另外一种工厂bean(FactoryBean)
2、普通bean:在配置文件中定义bean类型就是返回类型
3、工厂bean:在配置文件定义bean类型可以和返回类型不一样
第一步 创建类,让这个类作为工厂bean,实现接口 FactoryBean
第二步 实现接口里面的方法,在实现的方法中定义返回的bean类型
public class MyBean implements FactoryBean<Course> {
<span class="token comment">//定义返回bean</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token class-name">Course</span> <span class="token function">getObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{<!-- --></span> <span class="token class-name">Course</span> course <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Course</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> course<span class="token punctuation">.</span><span class="token function">setCname</span><span class="token punctuation">(</span><span class="token string">"abc"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> course<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation"><</span><span class="token operator">?</span><span class="token punctuation">></span></span> <span class="token function">getObjectType</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">isSingleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> <span class="token class-name">FactoryBean</span><span class="token punctuation">.</span><span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">isSingleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
<bean id="myBean" class="com.atguigu.spring5.factorybean.MyBean"> </bean>
@Test
public void testMyBean(){
//1.加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
//2.获取配置创建对象
Course course = context.getBean("myBean", Course.class);
System.out.println(course);
}
3.3 IOC操作 Bean 管理( bean 作用域)
1、在Spring里面,设置创建bean实例是单实例还是多实例
2、在Spring里面,默认情况下,bean是单实例对象
@Test public void testBook1(){ //1.加载配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml"); //2.获取配置创建对象 Book book = context.getBean("book", Book.class);
<span class="token class-name">Book</span> book1 <span class="token operator">=</span> context<span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span><span class="token string">"book"</span><span class="token punctuation">,</span> <span class="token class-name">Book</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>book<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>book1<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/*单例模式 book 和 book1 bean配置中scope = "singleton" com.atguigu.spring5.collectiontype.Book@7ba18f1b com.atguigu.spring5.collectiontype.Book@7ba18f1b*/</span> <span class="token comment">/* 多例模式 bean配置中scope = "prototype" com.atguigu.spring5.collectiontype.Book@7ba18f1b com.atguigu.spring5.collectiontype.Book@2f8f5f62 */</span>
}
<!--手动装配-->
<!-- <bean id="emp" class="com.atguigu.spring5.autowire.Emp">-->
<!-- <property name="dept" ref="dept"></property>-->
<!-- </bean>-->
<!-- <bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>-->
<!-- -->
<!-- 实现自动装配 -->
<bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byName"></bean>
<bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>
3、如何设置单实例还是多实例
(1)在spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例
(2)scope属性值
第一个值 默认值,singleton,表示是单实例对象
/单例模式 book 和 book1 bean配置中scope = “singleton”
com.atguigu.spring5.collectiontype.Book@7ba18f1b
com.atguigu.spring5.collectiontype.Book@7ba18f1b/
第二个值 prototype,表示是多实例对象
/* 多例模式 bean配置中scope = “prototype”
com.atguigu.spring5.collectiontype.Book@7ba18f1b
com.atguigu.spring5.collectiontype.Book@2f8f5f62
*/
3.4 IOC操作 Bean 管理( bean 生命周期)
1、生命周期
(1)从对象创建到对象销毁的过程
2、bean生命周期
(1)通过构造器创建bean实例(无参数构造)
(2)为bean的属性设置值和对其他bean引用(调用set方法)
(3)调用bean的初始化的方法(需要进行配置初始化的方法)
(4)bean可以使用了(对象获取到了)
(5)当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)
3、演示bean生命周期
public class Orders { private String oname;
<span class="token keyword">public</span> <span class="token class-name">Orders</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"第一步 执行无参构造创建bean实例"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setOname</span><span class="token punctuation">(</span><span class="token class-name">String</span> oname<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>oname <span class="token operator">=</span> oname<span class="token punctuation">;</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"第二步 调用set方法设置属性值"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">ininMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"第三步 执行初始化方法"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">destoryMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"第五步 执行销毁方法"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
<bean id="orders" class="com.atguigu.spring5.bean.Orders" init-method="ininMethod" destroy-method="destoryMethod">
<property name="oname" value="手机"></property>
</bean>
@Test
public void testOrders(){
//1.加载配置文件
// ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
//2.获取配置创建对象
Orders orders = context.getBean("orders", Orders.class);
System.out.println("第四步 获取创建bean实例对象");
System.out.println(orders);
//手动让bean实例销毁
// ((ClassPathXmlApplicationContext)context).close();
context.close();
}
4、bean的后置处理器,bean生命周期有七步
(1)通过构造器创建bean实例(无参数构造)
(2)为bean的属性设置值和对其他bean引用(调用set方法)
(3)把bean实例传递bean后置处理器的方法postProcessBeforeInitialization
(4)调用bean的初始化的方法(需要进行配置初始化的方法)
(5)把bean实例传递bean后置处理器的方法 postProcessAfterInitialization
(6)bean可以使用了(对象获取到了)
(7)当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)
5、演示添加后置处理器效果
(1)创建类,实现接口BeanPostProcessor,创建后置处理器
public class MyBeanPost implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("在初始化之前执行的方法"); return bean;
<span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">postProcessAfterInitialization</span><span class="token punctuation">(</span><span class="token class-name">Object</span> bean<span class="token punctuation">,</span> <span class="token class-name">String</span> beanName<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span> <span class="token punctuation">{<!-- --></span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"在初始化之后执行的方法"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> bean<span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
<!--配置后置处理器-->
<bean id="myBeanPost" class="com.atguigu.spring5.bean.MyBeanPost"></bean>
3.5 IOC操作 Bean 管理( xml 自动装配)
1、什么是自动装配
(1)根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入
2、演示自动装配过程
(1)根据属性名称自动注入
<!--<!– 手动装配 –>--> <!-- <bean id="emp" class="com.atguigu.spring5.autowire.Emp">--> <!-- <property name="dept" ref="dept"></property>--> <!-- </bean>-->
<!-- <bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>-->
<!-- --><!-- 实现自动装配
bean标签属性autowire,配置自动装配
autowire属性常用两个值:
byName 根据属性名称注入,注入值bean的id值和类属性名称一样
byType 根据属性类型注入-->
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>bean</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>emp<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.atguigu.spring5.autowire.Emp<span class="token punctuation">"</span></span> <span class="token attr-name">autowire</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>byName<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>bean</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>bean</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dept<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.atguigu.spring5.autowire.Dept<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>bean</span><span class="token punctuation">></span></span>
(2)根据属性类型自动注入
<bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byType"></bean>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>bean</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dept<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.atguigu.spring5.autowire.Dept<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>bean</span><span class="token punctuation">></span></span>
</beans>
3. 6 IOC操作 Bean 管理 外部属性文件
1、直接配置数据库信息
(1)配置德鲁伊连接池
(2)引入德鲁伊连接池依赖jar包
<!--直接配置连接池-->
<!-- <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">-->
<!-- <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>-->
<!-- <property name="url" value="jdbc:mysql://localhost:3306/userDb"></property>-->
<!-- <property name="username" value="root"></property>-->
<!-- <property name="password" value="root"></property>-->
<!-- </bean>-->
2、引入外部属性文件配置数据库连接池
(1)创建外部属性文件,properties格式文件,写数据库信息
(2)把外部properties属性文件引入到spring配置文件中
引入context名称空间
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
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/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
在spring配置文件使用标签引入外部属性文件
<!--使用外部属性文件配置数据库连接池-->
<!--引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.password}"></property>
</bean>
4 IOC操作 Bean 管理 基于注解方式
1、什么是注解
(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值…)
(2)使用注解,注解作用在类上面,方法上面,属性上面
(3)使用注解目的:简化xml配置
2、Spring针对Bean管理中创建对象提供注解
(1)@Component : 当前类标识为普通组件
(2)@Service : 业务层组件
(3)@Controller : 控制层组件
(4)@Repository : 持久层组件
上面四个注解功能是一样的,都可以用来创建bean实例
3、基于注解方式实现对象创建
第一步 引入依赖
第二步 开启组件扫描
<!--开启组件扫描
1) 如要要扫描多个包,可以用逗号隔开
2) 扫描包上层目录
-->
<!-- <context:component-scan base-package="com.atguigu.spring5.dao,com.atguigu.spring5.service"></context:component-scan>-->
<context:component-scan base-package="com.atguigu"></context:component-scan>
第三步 创建类,在类上面添加创建对象注解
//在注解里面value值可以不写 //默认为当前类的名称,首字母小写 //UserService --- userService //@Component(value = "userService") //<bean id="userService" class="...."> @Service public class UserService {
<span class="token comment">//定义dao类型属性</span> <span class="token comment">//不需要添加set()方法</span> <span class="token comment">//添加注入属性注解</span>
// @Autowired //根据类型进行注入
// @Qualifier(value = "userDAOImpl1") //根据名称进行注入 必须和@Autowired一起使用
// @Resource//根据类型进行注入
@Resource(name = "userDAOImpl1")//根据名称进行注入
private UserDAO userDAO;<span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"abc"</span><span class="token punctuation">)</span> <span class="token comment">//注入普通类型属性</span> <span class="token keyword">private</span> <span class="token class-name">String</span> name<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">add</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"service......."</span> <span class="token operator">+</span> name<span class="token punctuation">)</span><span class="token punctuation">;</span> userDAO<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
4、开启组件扫描细节配置
<!--组件扫描细节 示例1 use-default-filters="false" 表示不使用默认filter 自己配置filter context:include-filter :设置扫描哪些内容 --> <context:component-scan base-package="com.atguigu.spring5" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
<!--组件扫描细节 示例2
下面配置扫描包所有内容
context:exclude-filter :设置不扫描哪些内容
-->
<context:component-scan base-package="com.atguigu.spring5" >
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
5、基于注解方式实现属性注入
(1)@Autowired:根据属性类型进行自动装配
第一步 把service和dao对象创建,在service和dao类添加创建对象注解
第二步 在service注入dao对象,在service类添加dao类型属性,在属性上面使用注解
public interface UserDAO {
public void add();
}
@Repository(value = "userDAOImpl1")
public class UserDAOImpl implements UserDAO{
@Override
public void add() {
System.out.println("dao add.....");
}
}
@Service public class UserService {
<span class="token comment">//定义dao类型属性</span> <span class="token comment">//不需要添加set()方法</span> <span class="token comment">//添加注入属性注解</span>
// @Autowired //根据类型进行注入
// @Qualifier(value = "userDAOImpl1") //根据名称进行注入 必须和@Autowired一起使用// @Resource//根据类型进行注入
@Resource(name = "userDAOImpl1")//根据名称进行注入
private UserDAO userDAO;<span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"abc"</span><span class="token punctuation">)</span> <span class="token comment">//注入普通类型属性</span> <span class="token keyword">private</span> <span class="token class-name">String</span> name<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">add</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"service......."</span> <span class="token operator">+</span> name<span class="token punctuation">)</span><span class="token punctuation">;</span> userDAO<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
(2)@Qualifier:根据名称进行注入
这个@Qualifier注解的使用,和上面@Autowired一起使用
//定义dao类型属性
//不需要添加set()方法
//添加注入属性注解
// @Autowired //根据类型进行注入
// @Qualifier(value = "userDAOImpl1") //根据名称进行注入 必须和@Autowired一起使用
(3)@Resource:可以根据类型注入,可以根据名称注入
// @Resource//根据类型进行注入
@Resource(name = "userDAOImpl1")//根据名称进行注入
private UserDAO userDAO;
(4)@Value:注入普通类型属性
@Value(value = "abc") //注入普通类型属性
private String name;
6、完全注解开发
(1)创建配置类,替代xml配置文件
/**完全注解开发 ---可以将bean1.xml文件删除了 */ @Configuration //作为配置类,替代xml配置文件 @ComponentScan(basePackages = {"com.atguigu"}) public class SpringConfig {
}
(2)编写测试类
@Test public void testUserService1(){ //1.加载配置类 ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); //2.获取配置创建对象 UserService userService = context.getBean("userService", UserService.class);
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>userService<span class="token punctuation">)</span><span class="token punctuation">;</span> userService<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
}
Aop
1 概念
1、什么是AOP Aspect Oriented Programming
(1)面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
(2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能
(3)使用登录例子说明AOP
2 AOP底层原理
1、AOP底层使用动态代理
(1)有两种情况动态代理
第一种 有接口情况,使用JDK动态代理
创建接口实现类代理对象,增强类的方法
第二种 没有接口情况,使用CGLIB动态代理
创建子类的代理对象,增强类的方法
AOP动态代理(JDK代理)
1、使用JDK动态代理,使用Proxy类里面的方法创建代理对象
(1)调用newProxyInstance方法
方法有三个参数:
第一参数,类加载器
第二参数,增强方法所在的类,这个类实现的接口,支持多个接口
第三参数,实现这个接口InvocationHandler,创建代理对象,写增强的部分
2、编写JDK动态代理代码
(1)创建接口,定义方法
public interface UserDao {
public int add(int a,int b);
public String update(String id);
}
(2)创建接口实现类,实现方法
public class UserDaoImpl implements UserDao { @Override public int add(int a, int b) { System.out.println("add方法执行了....."); return a+b; }
<span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">update</span><span class="token punctuation">(</span><span class="token class-name">String</span> id<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"update方法执行了....."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> id<span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
(3)使用Proxy类创建接口代理对象
public class JDKProxy { public static void main(String[] args) { //创建接口实现类代理对象 Class[] interfaces = {UserDao.class}; // Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() { // @Override // public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // return null; // } // }); UserDaoImpl userDao = new UserDaoImpl(); UserDao dao = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); int result = dao.add(1, 2); System.out.println("result:"+result); } }
//创建代理对象代码
class UserDaoProxy implements InvocationHandler {<span class="token comment">//1 把创建的是谁的代理对象,把谁传递过来</span> <span class="token comment">//利用有参数构造传递</span> <span class="token keyword">private</span> <span class="token class-name">Object</span> obj<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token class-name">UserDaoProxy</span><span class="token punctuation">(</span><span class="token class-name">Object</span> obj<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>obj <span class="token operator">=</span> obj<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//增强的逻辑</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">invoke</span><span class="token punctuation">(</span><span class="token class-name">Object</span> proxy<span class="token punctuation">,</span> <span class="token class-name">Method</span> method<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">//方法之前</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"方法之前执行...."</span><span class="token operator">+</span>method<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">+</span><span class="token string">" :传递的参数..."</span><span class="token operator">+</span> <span class="token class-name">Arrays</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//被增强的方法执行</span> <span class="token class-name">Object</span> res <span class="token operator">=</span> method<span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span>obj<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//方法之后</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"方法之后执行...."</span><span class="token operator">+</span>obj<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> res<span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
AOP(术语)
1.连接点
2.切入点
3.通知(增强)
4.切面
AOP操作(准备 工作)
1、Spring框架一般都是基于AspectJ实现AOP操作
(1)AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spirng框架一起使用,进行AOP操作
2、基于AspectJ实现AOP操作
(1)基于xml配置文件实现
(2)基于注解方式实现(使用)
3、在项目工程里面引入AOP相关依赖
4、切入点表达式
(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构:execution([权限修饰符] [返回类型] [类全路径] 方法名称 )
举例1:对com.atguigu.dao.BookDao类里面的add进行增强
execution(* com.atguigu.dao.BookDao.add(…))
举例2:对com.atguigu.dao.BookDao类里面的所有的方法进行增强
execution(* com.atguigu.dao.BookDao.* (…))
举例3:对com.atguigu.dao包里面所有类,类里面所有方法进行增强
execution(* com.atguigu.dao.. (…))
AOP操作( AspectJ 注解)
1、创建类,在类里面定义方法
public class User { public void add(){ int i = 10 / 0;
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"add..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
2、创建增强类(编写增强逻辑)
(1)在增强类里面,创建方法,让不同方法代表不同通知类型
public class UserProxy {
public void before(){
System.out.println("before.....");
}
3、进行通知的配置
(1)在spring配置文件中,开启注解扫描
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" 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">
<span class="token comment"><!--开启注解扫描--></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token namespace">context:</span>component-scan</span> <span class="token attr-name">base-package</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.atguigu.spring5.aopanno<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token namespace">context:</span>component-scan</span><span class="token punctuation">></span></span>
(2)使用注解创建User和UserProxy对象
@Component public class User { @Component public class UserProxy {
(3)在增强类上面添加注解 @Aspect
@Component
@Aspect//生成代理对象
public class UserProxy {
(4)在spring配置文件中开启生成代理对象
<!--开启Aspect生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4、配置不同类型的通知
(1)在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
/**增强的类 */ @Component @Aspect//生成代理对象 @Order(3) public class UserProxy {
<span class="token comment">//前置通知</span> <span class="token comment">//@Before注解表示作为前置通知</span> <span class="token annotation punctuation">@Before</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"execution(* com.atguigu.spring5.aopanno.User.add(..))"</span><span class="token punctuation">)</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">before</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span><span class="token comment">//前置通知</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"before....."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//后置通知(返回通知)</span> <span class="token comment">//@AfterReturning注解表示作为返回通知(在方法返回结果之后执行)</span> <span class="token annotation punctuation">@AfterReturning</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"execution(* com.atguigu.spring5.aopanno.User.add(..))"</span><span class="token punctuation">)</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">afterReturning</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"AfterReturning....."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//最终通知</span> <span class="token comment">// @After注解表示作为最终通知(在方法执行之后执行;一定会执行的)</span> <span class="token annotation punctuation">@After</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"execution(* com.atguigu.spring5.aopanno.User.add(..))"</span><span class="token punctuation">)</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">after</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"After....."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//异常通知</span> <span class="token comment">//@AfterThrowing注解表示作为异常通知</span> <span class="token annotation punctuation">@AfterThrowing</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"execution(* com.atguigu.spring5.aopanno.User.add(..))"</span><span class="token punctuation">)</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">afterThrowing</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"afterThrowing....."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//环绕通知</span> <span class="token comment">//@Before注解表示作为环绕通知</span> <span class="token annotation punctuation">@Around</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"execution(* com.atguigu.spring5.aopanno.User.add(..))"</span><span class="token punctuation">)</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">around</span><span class="token punctuation">(</span><span class="token class-name">ProceedingJoinPoint</span> proceedingJoinPoint<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">{<!-- --></span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"环绕之前....."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//被增强的方法执行</span> proceedingJoinPoint<span class="token punctuation">.</span><span class="token function">proceed</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"环绕之后....."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
5、相同的切入点抽取
//相同切入点抽取
@Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void pointDemo(){
}
对比:
@Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
@Before("pointDemo()")
6、有多个增强类对同一个方法进行增强,设置增强类优先级
(1)在增强类上面添加注解==@Order(数字类型值),数字类型值越小优先级越高==
@Component
@Aspect
@Order(1)//数字越小,优先级越高
public class PersonProxy {
//前置通知
//@Before注解表示作为前置通知
@Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void before(){//前置通知
System.out.println("PersonProxy.....");
}
}
@Component
@Aspect//生成代理对象
@Order(3)
public class UserProxy {
7、完全使用注解开发
(1)创建配置类,不需要创建xml配置文件
@Configuration
@ComponentScan(basePackages = {"com.atguigu"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}
AOP操作( AspectJ 配置文件)
1、创建两个类,增强类和被增强类,创建方法
2、在spring配置文件中创建两个类对象
<!--创建对象-->
<bean id="book" class="com.atguigu.spring5.aopxml.Book"></bean>
<bean id="bookProxy" class="com.atguigu.spring5.aopxml.BookProxy"></bean>
3、在spring配置文件中配置切入点
<!--配置aop增强-->
<aop:config>
<!--切入点-->
<aop:pointcut id="p" expression="execution(* com.atguigu.spring5.aopxml.Book.buy(..))"/>
<!--配置切面-->
<aop:aspect ref="bookProxy">
<!--增强作用在具体的方法上-->
<aop:before method="before" pointcut-ref="p"/>
</aop:aspect>
</aop:config>
3 JdbcTemplate
概念和原理
1、什么是JdbcTemplate
(1)Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库操作
2、准备工作
(1)引入相关jar包
(2)在spring配置文件配置数据库连接池
<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<property name="url" value="jdbc:mysql:///user_db"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
</bean>
(3)配置JdbcTemplate对象,注入DataSource
<!--JdbcTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入dataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
(4)创建service类,创建dao类,在dao注入jdbcTemplate对象
配置文件
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.atguigu"></context:component-scan>
**Service** */@Service public class BookService {
<span class="token comment">//注入dao</span> <span class="token annotation punctuation">@Autowired</span> <span class="token keyword">private</span> <span class="token class-name">BookDAO</span> bookDAO<span class="token punctuation">;</span>
**Dao**
*/@Repository
public class BookDAOImpl implements BookDAO{
//注入jdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
JdbcTemplate操作数据库(添加)
1、对应数据库创建实体类
public class Book { private int userId; private String username; private String ustatus;
<span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">getUserId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> userId<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setUserId</span><span class="token punctuation">(</span><span class="token keyword">int</span> userId<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>userId <span class="token operator">=</span> userId<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">getUsername</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> username<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setUsername</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>username <span class="token operator">=</span> username<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">getUstatus</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> ustatus<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setUstatus</span><span class="token punctuation">(</span><span class="token class-name">String</span> ustatus<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>ustatus <span class="token operator">=</span> ustatus<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> <span class="token string">"Book{"</span> <span class="token operator">+</span> <span class="token string">"userId="</span> <span class="token operator">+</span> userId <span class="token operator">+</span> <span class="token string">", username='"</span> <span class="token operator">+</span> username <span class="token operator">+</span> <span class="token char">'\''</span> <span class="token operator">+</span> <span class="token string">", ustatus='"</span> <span class="token operator">+</span> ustatus <span class="token operator">+</span> <span class="token char">'\''</span> <span class="token operator">+</span> <span class="token char">'}'</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
2、编写service和dao
(1)在dao进行数据库添加操作
(2)调用JdbcTemplate对象里面update方法实现添加操作
⚫ 有两个参数
⚫ 第一个参数:sql语句
⚫ 第二个参数:可变参数,设置sql语句值
*/@Repository public class BookDAOImpl implements BookDAO{
<span class="token comment">//注入jdbcTemplate</span> <span class="token annotation punctuation">@Autowired</span> <span class="token keyword">private</span> <span class="token class-name">JdbcTemplate</span> jdbcTemplate<span class="token punctuation">;</span> <span class="token comment">//添加的方法</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">add</span><span class="token punctuation">(</span><span class="token class-name">Book</span> book<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">//1 创建sql语句</span> <span class="token class-name">String</span> sql <span class="token operator">=</span> <span class="token string">"insert into t_book values(?,?,?)"</span><span class="token punctuation">;</span> <span class="token comment">//2 调用方法实现</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args <span class="token operator">=</span> <span class="token punctuation">{<!-- --></span>book<span class="token punctuation">.</span><span class="token function">getUserId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>book<span class="token punctuation">.</span><span class="token function">getUsername</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>book<span class="token punctuation">.</span><span class="token function">getUstatus</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">int</span> update <span class="token operator">=</span> jdbcTemplate<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span>sql<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>update<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
3、测试类
@Test public void testJdbcTemplate() {//添加方法测试 //1.加载配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); //2.获取配置创建对象 BookService bookService = context.getBean("bookService", BookService.class); Book book = new Book(); book.setUsername("java1"); book.setUserId(2); book.setUstatus("b"); bookService.add(book);
}
JdbcTemplate操作数据库(修改和删除)
1.修改
//修改的方法
@Override
public void update(Book book) {
//1.创建sql语句
String sql = "update t_book set username = ?, ustatus = ? where userId=?";
//2.调用方法实现
Object[] args = {book.getUsername(),book.getUstatus(),book.getUserId()};
int update = jdbcTemplate.update(sql, args); //受影响的行数
System.out.println(update);
}
2.删除
//删除的方法
@Override
public void delete(String id) {
//1.创建sql语句
String sql = "delete from t_book where userId = ?";
//2.调用方法实现
int delete = jdbcTemplate.update(sql, id); //受影响的行数
System.out.println(delete);
}
JdbcTemplate操作数据库(查询返回某个值)
1、查询表里面有多少条记录,返回是某个值
2、使用JdbcTemplate实现查询返回某个值代码
⚫ 有两个参数
⚫ 第一个参数:sql语句
⚫ 第二个参数:返回类型Class
//查询表记录数
@Override
public int findCount() {
String sql = "select count(*) from t_book";
//2.调用方法实现
Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
return count;
}
JdbcTemplate操作数据库(查询返回对象)
⚫ 有三个参数
⚫ 第一个参数:sql语句
⚫ 第二个参数:RowMapper是接口,针对返回不同类型数据,使用这个接口里面实现类完成数据封装
⚫ 第三个参数:sql语句
//查询返回对象 @Override public Book findOne(String id) {
<span class="token class-name">String</span> sql <span class="token operator">=</span> <span class="token string">"select * from t_book where userId = ?"</span><span class="token punctuation">;</span> <span class="token comment">//2.调用方法实现</span> <span class="token class-name">Book</span> book <span class="token operator">=</span> jdbcTemplate<span class="token punctuation">.</span><span class="token function">queryForObject</span><span class="token punctuation">(</span>sql<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">BeanPropertyRowMapper</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Book</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token class-name">Book</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">,</span> id<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> book<span class="token punctuation">;</span>
}
JdbcTemplate操作数据库(查询返回集合)
1、场景:查询图书列表分页…
2、调用JdbcTemplate方法实现查询返回集合
⚫ 有三个参数
⚫ 第一个参数:sql语句
⚫ 第二个参数:RowMapper是接口,针对返回不同类型数据,使用这个接口里面实现类完成数据封装
⚫ 第三个参数:sql语句值
//查询返回集合
@Override
public List<Book> findAll() {
String sql = "select * from t_book";
//2.调用方法实现
List<Book> bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class));
return bookList;
}
JdbcTemplate操作数据库 (批量操作)
1、批量操作:操作表里面多条记录
2、JdbcTemplate实现批量添加操作
有两个参数
⚫ 第一个参数:sql语句
⚫ 第二个参数:List集合,添加多条记录数据
//批量添加 @Override public void batchAddBook(List<Object[]> batchArgs) { String sql = "insert into t_book values(?,?,?)";
<span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> ints <span class="token operator">=</span> jdbcTemplate<span class="token punctuation">.</span><span class="token function">batchUpdate</span><span class="token punctuation">(</span>sql<span class="token punctuation">,</span> batchArgs<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//返回受影响的行数</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">Arrays</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span>ints<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
}
@Test
public void testJdbcTemplate6() {//批量添加测试
//1.加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2.获取配置创建对象
BookService bookService = context.getBean("bookService", BookService.class);
List<Object[]> batchArgs = new ArrayList<>();
Object[] o1 = {"3", "java", "a"};
Object[] o2 = {"4", "c++", "b"};
Object[] o3 = {"5", "MySQL", "c"};
batchArgs.add(o1);
batchArgs.add(o2);
batchArgs.add(o3);
//调用批量添加
bookService.batchAdd(batchArgs);
}
3、JdbcTemplate实现批量修改操作
//批量修改 @Override public void batchUpdateBook(List<Object[]> batchArgs) { String sql = "update t_book set username = ?, ustatus = ? where userId = ?"; int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs); System.out.println(Arrays.toString(ints));
}
@Test
public void testJdbcTemplate7() {//批量修改测试
//1.加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2.获取配置创建对象
BookService bookService = context.getBean("bookService", BookService.class);
List<Object[]> batchArgs = new ArrayList<>();
Object[] o1 = { "java0909", "aaaa","3"};
Object[] o2 = {"c++1010", "bbbb","4" };
Object[] o3 = { "MySQL1212", "cccc","5"};
batchArgs.add(o1);
batchArgs.add(o2);
batchArgs.add(o3);
//调用批量添加
bookService.batchUpdate(batchArgs);
}
4、JdbcTemplate实现批量删除操作
//批量删除 @Override public void batchDeleteBook(List<Object[]> batchArgs) { String sql = "delete from t_book where userId = ?"; int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs); System.out.println(Arrays.toString(ints)); }
@Test
public void testJdbcTemplate8() {//批量删除测试
//1.加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2.获取配置创建对象
BookService bookService = context.getBean("bookService", BookService.class);
List<Object[]> batchArgs = new ArrayList<>();
Object[] o1 = {"3"};
Object[] o2 = {"4"};
Object[] o3 = {"5"};
batchArgs.add(o1);
batchArgs.add(o2);
batchArgs.add(o3);
//调用批量添加
bookService.batchDelete(batchArgs);
}
4 事务管理
事务操作过程
public void accountMoney(){
// try {
<span class="token comment">//第一步 开启事务</span> <span class="token comment">//第二步 进行业务操作</span> <span class="token comment">//lucy 少100</span> userDAO<span class="token punctuation">.</span><span class="token function">reduceMoney</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//模拟异常</span> <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">10</span> <span class="token operator">/</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token comment">//mary 多100</span> userDAO<span class="token punctuation">.</span><span class="token function">addMoney</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//第三步,如果没有异常,提交事务</span>
// }catch(Exception e){
<span class="token comment">//第四步,出现异常,回滚事务</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
事务操作(Spring 事务管理介绍)
1、事务添加到JavaEE三层结构里面Service层(业务逻辑层)
2、在Spring进行事务管理操作
(1)有两种方式:编程式事务管理和声明式事务管理(使用)
3、声明式事务管理
(1)基于注解方式(使用)
(2)基于xml配置文件方式
4、在Spring进行声明式事务管理,底层使用AOP原理
5、Spring事务管理API
(1)提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
事务操作(声明式事务管理参数配置)
1、在service类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数
2、propagation:事务传播行为
(1)多事务方法之间进行调用,这个过程中事务 是如何进行管理的
@Service
@Transactional(propagation = Propagation.REQUIRED)
public class UserService {
3、isolation:事务隔离级别
(1)事务有特性成为隔离性,多事务操作之间不会产生影响。不考虑隔离性产生很多问题
(2)有三个读问题:脏读、不可重复读、虚(幻)读
(3)脏读:一个未提交事务读取到另一个未提交事务的数据
(4)不可重复读:一个未提交事务读取到另一提交事务修改数据
(5)虚读:一个未提交事务读取到另一提交事务添加数据
(6)解决:通过设置事务隔离级别,解决读问题
*/@Service
@Transactional(timeout = 5,propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
public class UserService {
4、timeout:超时时间
(1)事务需要在一定时间内进行提交,如果不提交进行回滚
(2)默认值是 -1 ,设置时间以秒单位进行计算
5、readOnly:是否只读
(1)读:查询操作,写:添加修改删除操作
(2)readOnly默认值false,表示可以查询,可以添加修改删除操作
(3)设置readOnly值是true,设置成true之后,只能查询
6、rollbackFor:回滚
(1)设置出现哪些异常进行事务回滚
7、noRollbackFor:不回滚
(1)设置出现哪些异常不进行事务回滚
事务操作(XML 声明式事务管理)
1、在spring配置文件中进行配置
第一步 配置事务管理器
第二步 配置通知
第三步 配置切入点和切面
<!-- 开启注解扫描 --> <context:component-scan base-package="com.atguigu"></context:component-scan>
<span class="token comment"><!-- 数据库连接池 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>bean</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dataSource<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.alibaba.druid.pool.DruidDataSource<span class="token punctuation">"</span></span> <span class="token attr-name">destroy-method</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>close<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>url<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>jdbc:mysql://localhost:13306/userdb<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>username<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>root<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>5864@WCY<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>driverClassName<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>com.mysql.jdbc.Driver<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>bean</span><span class="token punctuation">></span></span> <span class="token comment"><!--JdbcTemplate对象--></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>bean</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>jdbcTemplate<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>org.springframework.jdbc.core.JdbcTemplate<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token comment"><!--注入dataSource--></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dataSource<span class="token punctuation">"</span></span> <span class="token attr-name">ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dataSource<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>property</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>bean</span><span class="token punctuation">></span></span> <span class="token comment"><!-- 1 创建事务管理器--></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>bean</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>transactionManager<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>org.springframework.jdbc.datasource.DataSourceTransactionManager<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token comment"><!--注入数据源--></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dataSource<span class="token punctuation">"</span></span> <span class="token attr-name">ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dataSource<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>property</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>bean</span><span class="token punctuation">></span></span>
<!-- 2 配置通知 -->
<tx:advice id="txadive">
<!--配置事务参数-->
<tx:attributes>
<!--指定哪种规则的方法上面添加事务-->
<tx:method name="accountMoney" propagation="REQUIRED"/>
<!-- <tx:method name="account*"></tx:method>-->
</tx:attributes>
</tx:advice><span class="token comment"><!--3 配置切入点和切面--></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token namespace">aop:</span>config</span><span class="token punctuation">></span></span> <span class="token comment"><!--配置切入点--></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token namespace">aop:</span>pointcut</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pt<span class="token punctuation">"</span></span> <span class="token attr-name">expression</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>execution(* com.atguigu.spring5.service.UserService.*(..))<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token comment"><!--配置切面--></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token namespace">aop:</span>advisor</span> <span class="token attr-name">advice-ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>txadive<span class="token punctuation">"</span></span> <span class="token attr-name">pointcut-ref</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>pt<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token namespace">aop:</span>config</span><span class="token punctuation">></span></span>
事务操作(完全注解声明式事务管理)
1、创建配置类,使用配置类替代xml配置文件
@Configuration //配置类 @ComponentScan(basePackages = "com.atguigu") //组件扫描 @EnableTransactionManagement //开启事务 public class TxConfig { //创建数据库连接池 @Bean public DruidDataSource getDruidDataSource(){ DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:13306/userdb"); dataSource.setUsername("root"); dataSource.setPassword("5864@WCY"); return dataSource; }
<span class="token comment">//创建JdbcTemplate对象</span> <span class="token annotation punctuation">@Bean</span> <span class="token keyword">public</span> <span class="token class-name">JdbcTemplate</span> <span class="token function">getJdbcTemplate</span><span class="token punctuation">(</span><span class="token class-name">DataSource</span> dataSource<span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> <span class="token comment">//到ioc容器中根据类型找到dataSource</span> <span class="token class-name">JdbcTemplate</span> jdbcTemplate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">JdbcTemplate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//注入dataSource</span> jdbcTemplate<span class="token punctuation">.</span><span class="token function">setDataSource</span><span class="token punctuation">(</span>dataSource<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> jdbcTemplate<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//创建事务管理器</span> <span class="token annotation punctuation">@Bean</span> <span class="token keyword">public</span> <span class="token class-name">DataSourceTransactionManager</span> <span class="token function">getDataSourceTransactionManager</span><span class="token punctuation">(</span><span class="token class-name">DataSource</span> dataSource<span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> <span class="token class-name">DataSourceTransactionManager</span> transactionManager <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DataSourceTransactionManager</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> transactionManager<span class="token punctuation">.</span><span class="token function">setDataSource</span><span class="token punctuation">(</span>dataSource<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> transactionManager<span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
5 spring5新特性
1、整个Spring5框架的代码基于Java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除
2、Spring 5.0框架自带了通用的日志封装
3、Spring5框架核心容器支持@Nullable注解
4、Spring5核心容器支持函数式风格GenericApplicationContext
5、Spring5支持整合JUnit5
6、Spring5框架 新功能 Webflux
6、1SpringWebflux介绍
6、2 响应式编程(Java实现)
6、3 响应式编程(Reactor实现)
6、4 SpringWebflux执行流程和核心API
6、5 SpringWebflux(基于注解编程模型)
6、6 SpringWebflux(基于函数式编程模型)
1.IOC常用注解
注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值…)
创建对象的注解 | 功能 |
---|---|
@Component | 当前类标识为普通组件 |
@Service | 业务层组件 |
@Controller | 控制层组件 |
@Repository | 持久层组件 |
为对象注入属性的注解 | 功能 |
---|---|
@Autowired | 根据属性类型进行自动装配 |
@Qualifier | 根据名称进行注入(需要和@Autowired一起使用) |
@Resource | 可以根据类型注入,可以根据名称注入 |
@Value | 注入普通类型属性 |
完全注解开发 | 功能 |
---|---|
@Configuration | 作为配置类,替代xml配置文件 |
2.AOP常用注解
注解 | 功能 |
---|---|
@Aspect | 生成代理对象 |
@Before | 表示作为前置通知 |
@AfterReturning | 表示作为返回通知(在方法返回结果之后执行) |
@After | 表示作为最终通知(在方法执行之后执行;一定会执行的) |
@AfterThrowing | 表示作为异常通知 |
@Before | 表示作为环绕通知 |
@Pointcut | 相同切入点抽取 |
@Order | 设置增强类优先级(数字类型值越小优先级越高) |
@ComponentScan | 开启注解扫描(组件扫描) |
@EnableAspectJAutoProxy | 开启AOP代理自动配置 |
3.事务注解
注解 | 功能 |
---|---|
@Transactional | 开启事务(在这个注解里面配置事务相关参数) |
@EnableTransactionManagement | 开启事务 |
4.spring5框架新功能
注解 | 功能 |
---|---|
@Nullable注解 | 可以使用在方法上面,属性上面,参数上面,表示方法返回可以为空,属性值可以为空,参数值可以为空 |
@RunWith | 单元测试框架 |
@ContextConfiguration | 加载配置文件 |
@SpringJUnitConfig | 复合注解 |
三、 springMVC
1 MVC简介
MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分。
M:Model,模型层,指工程中的JavaBean,作用是处理数据
JavaBean分为两类:
一类称为实体类Bean:专门存储业务数据的,如 Student、User 等
一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。
V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据
C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器
MVC的工作流程:用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器
2 springmvc
SpringMVC是Spring的一个后续产品,是Spring的一个子项目
SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 Strust、WebWork、Strust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 Java EE 项目表述层开发的首选方案。
注:三层架构分为表述层(或表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台servlet
3 SpringMVC的特点
Spring 家族原生产品,与 IOC 容器等基础设施无缝对接
基于原生的Servlet,通过了功能强大的前端控制器DispatcherServlet,对请求和响应进行统一处理
表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案
代码清新简洁,大幅度提升开发效率
内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
性能卓著,尤其适合现代大型、超大型互联网项目要求
4 测试springMVC
1、开发环境
IDE:idea 2019.2
构建工具:maven3.5.4
服务器:tomcat7
Spring版本:5.3.1
2、创建maven工程
a>添加web模块
b>打包方式:war
c>引入依赖
<dependencies>
<!-- SpringMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.1</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- ServletAPI -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- Spring5和Thymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
</dependencies>
注:由于 Maven 的传递性,我们不必将所有需要的包全部配置依赖,而是配置最顶端的依赖,其他靠传递性导入。
3、配置web.xml
注册SpringMVC的前端控制器DispatcherServlet
a>默认配置
此配置作用下,SpringMVC的配置文件默认位于WEB-INF下,默认名称为
<servlet-name>-servlet.xml
,例如,以下配置所对应SpringMVC的配置文件位于WEB-INF下,文件名为springMVC-servlet.xml
<!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 --> <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>springMVC</servlet-name> <!-- 设置springMVC的核心控制器所能处理的请求的请求路径 /所匹配的请求可以是/login或.html或.js或.css方式的请求路径 但是/不能匹配.jsp请求路径的请求 --> <url-pattern>/</url-pattern> </servlet-mapping>
b>扩展配置方式
可通过init-param标签设置SpringMVC配置文件的位置和名称,通过load-on-startup标签设置SpringMVC前端控制器DispatcherServlet的初始化时间
<!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 -->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 通过初始化参数指定SpringMVC配置文件的位置和名称 -->
<init-param>
<!-- contextConfigLocation为固定值 -->
<param-name>contextConfigLocation</param-name>
<!-- 使用classpath:表示从类路径查找配置文件,例如maven工程中的src/main/resources -->
<param-value>classpath:springMVC.xml</param-value>
</init-param>
<!--
作为框架的核心组件,在启动过程中有大量的初始化操作要做
而这些操作放在第一次请求时才执行会严重影响访问速度
因此需要通过此标签将启动控制DispatcherServlet的初始化时间提前到服务器启动时
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<!--
设置springMVC的核心控制器所能处理的请求的请求路径
/所匹配的请求可以是/login或.html或.js或.css方式的请求路径
但是/不能匹配.jsp请求路径的请求
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
注:<url-pattern>
标签中使用/和/*的区别:/所匹配的请求可以是/login或.html或.js或.css方式的请求路径,但是/不能匹配.jsp请求路径的请求。
因此就可以避免在访问jsp页面时,该请求被DispatcherServlet处理,从而找不到相应的页面
/则能够匹配所有请求,例如在使用过滤器时,若需要对所有请求进行过滤,就需要使用 / 的写法
4、创建请求控制器
由于前端控制器对浏览器发送的请求进行了统一的处理,但是具体的请求有不同的处理过程,因此需要创建处理具体请求的类,即请求控制器
请求控制器中每一个处理请求的方法成为控制器方法
因为SpringMVC的控制器由一个POJO(普通的Java类)担任,因此需要通过@Controller注解将其标识为一个控制层组件,交给Spring的IoC容器管理,此时SpringMVC才能够识别控制器的存在
@Controller public class HelloController {
}
5、创建springMVC的配置文件
<!-- 自动扫描包 --> <context:component-scan base-package="com.atguigu.mvc.controller"/> <!-- 配置Thymeleaf视图解析器 --> <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver"> <property name="order" value="1"/> <property name="characterEncoding" value="UTF-8"/> <property name="templateEngine"> <bean class="org.thymeleaf.spring5.SpringTemplateEngine"> <property name="templateResolver"> <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<span class="token comment"><!-- 视图前缀 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>prefix<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/WEB-INF/templates/<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token comment"><!-- 视图后缀 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>suffix<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.html<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>templateMode<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>HTML5<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>property</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>characterEncoding<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>UTF-8<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>bean</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>property</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>bean</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>property</span><span class="token punctuation">></span></span>
</bean>
<!--
处理静态资源,例如html、js、css、jpg
若只设置该标签,则只能访问静态资源,其他请求则无法访问
此时必须设置<mvc:annotation-driven/>解决问题
-->
<mvc:default-servlet-handler/>
<!-- 开启mvc注解驱动 -->
<mvc:annotation-driven>
<mvc:message-converters>
<!-- 处理响应中文内容乱码 -->
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="defaultCharset" value="UTF-8" />
<property name="supportedMediaTypes">
<list>
<value>text/html</value>
<value>application/json</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
在请求控制器中创建处理请求的方法
// @RequestMapping注解:处理请求和控制器方法之间的映射关系
// @RequestMapping注解的value属性可以通过请求地址匹配请求,/表示的当前工程的上下文路径
// localhost:8080/springMVC/
@RequestMapping("/")
public String index() {
//设置视图名称
return "index";
}
b>通过超链接跳转到指定页面
在主页index.html中设置超链接
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>首页</h1>
<a th:href="@{/hello}">HelloWorld</a><br/>
</body>
</html>
在请求控制器中创建处理请求的方法
@RequestMapping("/hello")
public String HelloWorld() {
return "target";
}
7、总结
浏览器发送请求,若请求地址符合前端控制器的url-pattern,该请求就会被前端控制器DispatcherServlet处理。前端控制器会读取SpringMVC的核心配置文件,通过扫描组件找到控制器,将请求地址和控制器中@RequestMapping注解的value属性值进行匹配,若匹配成功,该注解所标识的控制器方法就是处理请求的方法。处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析,加上前缀和后缀组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发到视图所对应页面
5 @RequestMaping注解
1、@RequestMapping注解的功能
从注解名称上我们可以看到,@RequestMapping注解的作用就是将请求和处理请求的控制器方法关联起来,建立映射关系。
SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的控制器方法来处理这个请求。
2、@RequestMapping注解的位置
@RequestMapping标识一个类:设置映射请求的请求路径的初始信息
@RequestMapping标识一个方法:设置映射请求请求路径的具体信息
@Controller
@RequestMapping("/test")
public class RequestMappingController {
//此时请求映射所映射的请求的请求路径为:/test/testRequestMapping
@RequestMapping("/testRequestMapping")
public String testRequestMapping(){
return "success";
}
}
3、@RequestMapping注解的value属性
@RequestMapping注解的value属性通过请求的请求地址匹配请求映射
@RequestMapping注解的value属性是一个字符串类型的数组,表示该请求映射能够匹配多个请求地址所对应的请求
@RequestMapping注解的value属性必须设置,至少通过请求地址匹配请求映射
<a th:href="@{/testRequestMapping}">测试@RequestMapping的value属性-->/testRequestMapping</a><br>
<a th:href="@{/test}">测试@RequestMapping的value属性-->/test</a><br>
@RequestMapping(
value = {"/testRequestMapping", "/test"}
)
public String testRequestMapping(){
return "success";
}
4、@RequestMapping注解的method属性
@RequestMapping注解的method属性通过请求的请求方式(get或post)匹配请求映射
@RequestMapping注解的method属性是一个RequestMethod类型的数组,表示该请求映射能够匹配多种请求方式的请求
若当前请求的请求地址满足请求映射的value属性,但是请求方式不满足method属性,则浏览器报错405:Request method 'POST' not supported
<a th:href="@{/test}">测试@RequestMapping的value属性-->/test</a><br>
<form th:action="@{/test}" method="post">
<input type="submit">
</form>
@RequestMapping(
value = {"/testRequestMapping", "/test"},
method = {RequestMethod.GET, RequestMethod.POST}
)
public String testRequestMapping(){
return "success";
}
注:1、对于处理指定请求方式的控制器方法,SpringMVC中提供了@RequestMapping的派生注解:
处理get请求的映射–>@GetMapping
处理post请求的映射–>@PostMapping
处理put请求的映射–>@PutMapping
处理delete请求的映射–>@DeleteMapping
2、常用的请求方式有get,post,put,delete但是目前浏览器只支持get和post,若在form表单提交时,为method设置了其他请求方式的字符串(put或delete),则按照默认的请求方式get处理若要发送put和delete请求,则需要通过spring提供的过滤器HiddenHttpMethodFilter,在RESTful部分会讲到
5、@RequestMapping注解的params属性(了解)
@RequestMapping注解的params属性通过请求的请求参数匹配请求映射
@RequestMapping注解的params属性是一个字符串类型的数组,可以通过四种表达式设置请求参数和请求映射的匹配关系
“param”:要求请求映射所匹配的请求必须携带param请求参数
“!param”:要求请求映射所匹配的请求必须不能携带param请求参数
“param=value”:要求请求映射所匹配的请求必须携带param请求参数且param=value
“param!=value”:要求请求映射所匹配的请求必须携带param请求参数但是param!=value
<a th:href="@{/test(username='admin',password=123456)">测试@RequestMapping的params属性-->/test</a><br>
@RequestMapping(
value = {"/testRequestMapping", "/test"}
,method = {RequestMethod.GET, RequestMethod.POST}
,params = {"username","password!=123456"}
)
public String testRequestMapping(){
return "success";
}
注:若当前请求满足@RequestMapping注解的value和method属性,但是不满足params属性,此时页面报错400:Parameter conditions "username, password!=123456" not met for actual request parameters: username={admin}, password={123456}
6、@RequestMapping注解的headers属性(了解)
@RequestMapping注解的headers属性通过请求的请求头信息匹配请求映射
@RequestMapping注解的headers属性是一个字符串类型的数组,可以通过四种表达式设置请求头信息和请求映射的匹配关系
“header”:要求请求映射所匹配的请求必须携带header请求头信息
“!header”:要求请求映射所匹配的请求必须不能携带header请求头信息
“header=value”:要求请求映射所匹配的请求必须携带header请求头信息且header=value
“header!=value”:要求请求映射所匹配的请求必须携带header请求头信息且header!=value
若当前请求满足@RequestMapping注解的value和method属性,但是不满足headers属性,此时页面显示404错误,即资源未找到
7、SpringMVC支持ant风格的路径
?:表示任意的单个字符
*:表示任意的0个或多个字符
:表示任意的一层或多层目录
注意:在使用时,只能使用/**/xxx的方式
8、SpringMVC支持路径中的占位符(重点)
原始方式:/deleteUser?id=1
rest方式:/deleteUser/1
SpringMVC路径中的占位符常用于RESTful风格中,当请求路径中将某些数据通过路径的方式传输到服务器中,就可以在相应的@RequestMapping注解的value属性中通过占位符{xxx}表示传输的数据,再通过**@PathVariable**注解,将占位符所表示的数据赋值给控制器方法的形参
<a th:href="@{/testRest/1/admin}">测试路径中的占位符-->/testRest</a><br>
@RequestMapping("/testRest/{id}/{username}")
public String testRest(@PathVariable("id") String id, @PathVariable("username") String username){
System.out.println("id:"+id+",username:"+username);
return "success";
}
//最终输出的内容为–>id:1,username:admin
9、总结报错情况
如果当前请求和RequestMapping中的任何一个value属性不匹配,报404
如果当前请求方式匹配不了,报405 请求方式不被支持
如果请求参数匹配不了,报400 传输参数不一致
请求头信息不匹配,报404
6 SpringMVC获取请求参数
1、通过ServletAPI获取
将HttpServletRequest作为控制器方法的形参,此时HttpServletRequest类型的参数表示封装了当前请求的请求报文的对象
@RequestMapping("/testParam")
public String testParam(HttpServletRequest request){
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("username:"+username+",password:"+password);
return "success";
}
2、通过控制器方法的形参获取请求参数
在控制器方法的形参位置,设置和请求参数同名的形参,当浏览器发送请求,匹配到请求映射时,在DispatcherServlet中就会将请求参数赋值给相应的形参
<a th:href="@{/testParam(username='admin',password=123456)}">测试获取请求参数-->/testParam</a><br>
@RequestMapping("/testParam")
public String testParam(String username, String password){
System.out.println("username:"+username+",password:"+password);
return "success";
}
注:若请求所传输的请求参数中有多个同名的请求参数,此时可以在控制器方法的形参中设置字符串数组或者字符串类型的形参接收此请求参数
若使用字符串数组类型的形参,此参数的数组中包含了每一个数据若使用字符串类型的形参,此参数的值为每个数据中间使用逗号拼接的结果
3、@RequestParam
@RequestParam是将请求参数和控制器方法的形参创建映射关系
@RequestParam注解一共有三个属性:
value:指定为形参赋值的请求参数的参数名
required:设置是否必须传输此请求参数,默认值为true
若设置为true时,则当前请求必须传输value所指定的请求参数,若没有传输该请求参数,且没有设置defaultValue属性,则页面报错400:Required String parameter 'xxx' is not present
;若设置为false,则当前请求不是必须传输value所指定的请求参数,若没有传输,则注解所标识的形参的值为null
defaultValue:不管required属性值为true或false,当value所指定的请求参数==没有传输或传输的值为""==时,则使用默认值为形参赋值
@RequestMapping("/testParam")
public String testParam(
@RequestParam(value = "user_name",required = false,defaultValue = "hehe") String username,
String password,
String[] hobbies,
@RequestHeader(value = "sayhaha",required = false,defaultValue = "haha") String host,
@CookieValue(value = "JSESSIONID") String JSESSIONID){
//若请求参数中出现多个同名的请求参数,可以在控制器方法的形参位置设置字符串类型或字符串数组接收此请求参数
//若使用字符串类型的参数,最终结果为请求参数的每一个值之间使用逗号进行拼接
System.out.println("username:" + username + ",password:" + password + ",hobbies"+ Arrays.toString(hobbies));
System.out.println("host:" + host);
System.out.println("JSESSIONID:" + JSESSIONID);
return "success";
4、@RequestHeader
@RequestHeader是将请求头信息和控制器方法的形参创建映射关系
@RequestHeader注解一共有三个属性:value、required、defaultValue,用法同@RequestParam
5、@CookieValue
@CookieValue是将cookie数据和控制器方法的形参创建映射关系
@CookieValue注解一共有三个属性:value、required、defaultValue,用法同@RequestParam
6、通过POJO获取请求参数
可以在控制器方法的形参位置设置一个实体类类型的形参,此时若浏览器传输的请求参数的参数名和实体类中的属性名一致,那么请求参数就会为此属性赋值
<form th:action="@{/testpojo}" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
性别:<input type="radio" name="sex" value="男">男<input type="radio" name="sex" value="女">女<br>
年龄:<input type="text" name="age"><br>
邮箱:<input type="text" name="email"><br>
<input type="submit">
</form>
public class User { private Integer id; private String username; private String password; private String sex; private Integer age; private String email; public User() { } public User(Integer id, String username, String password, String sex, Integer age, String email) {
<span class="token keyword">this</span><span class="token punctuation">.</span>id <span class="token operator">=</span> id<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>username <span class="token operator">=</span> username<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>password <span class="token operator">=</span> password<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>sex <span class="token operator">=</span> sex<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>age <span class="token operator">=</span> age<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>email <span class="token operator">=</span> email<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token class-name">Integer</span> <span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> id<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setId</span><span class="token punctuation">(</span><span class="token class-name">Integer</span> id<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>id <span class="token operator">=</span> id<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">getUsername</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> username<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setUsername</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>username <span class="token operator">=</span> username<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">getPassword</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> password<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setPassword</span><span class="token punctuation">(</span><span class="token class-name">String</span> password<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>password <span class="token operator">=</span> password<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">getSex</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> sex<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setSex</span><span class="token punctuation">(</span><span class="token class-name">String</span> sex<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>sex <span class="token operator">=</span> sex<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token class-name">Integer</span> <span class="token function">getAge</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> age<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setAge</span><span class="token punctuation">(</span><span class="token class-name">Integer</span> age<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>age <span class="token operator">=</span> age<span class="token punctuation">;</span> <span class="token punctuation">}</span>
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + ''' +
", password='" + password + ''' +
", sex='" + sex + ''' +
", age=" + age +
", email='" + email + ''' +
'}';
}
}
@RequestMapping("/testpojo")
public String testPOJO(User user){
System.out.println(user);
return "success";
}
//最终结果-->User{id=null, username='张三', password='123', age=23, sex='男', email='123@qq.com'}
7、解决获取请求参数的乱码问题
解决获取请求参数的乱码问题,可以使用SpringMVC提供的编码过滤器CharacterEncodingFilter,但是必须在web.xml中进行注册
<!--配置springMVC的编码过滤器-->
<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>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注:SpringMVC中处理编码的过滤器一定要配置到其他过滤器之前,否则无效
7 域对象共享数据
1、使用ServletAPI向request域对象共享数据
//使用servletAPI向request域对象共享数据 @RequestMapping("/testRequestByServletAPI") public String testRequestByServletAPI(HttpServletRequest request){ request.setAttribute("testRequestScope","hello,servletAPI");//向request共享作用域域中设置键,值 return "success";
}
2、使用ModelAndView向request域对象共享数据
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
/**
* ModelAndView有Model和View的功能
* Model主要用于向请求域共享数据
* View主要用于设置视图,实现页面跳转
*/
ModelAndView mav = new ModelAndView();
//向请求域共享数据
mav.addObject("testScope", "hello,ModelAndView");
//设置视图,实现页面跳转
mav.setViewName("success");
return mav;
}
3、使用Model向request域对象共享数据
//使用Model向request域对象共享数据
@RequestMapping("/testModel")
public String testModel(Model model){
model.addAttribute("testRequestScope","hello,Model");
System.out.println(model.getClass().getName());
return "success";
}
4、使用map向request域对象共享数据
//使用Map集合向request域对象共享数据
@RequestMapping("/testMap")
public String testMap(Map<String,Object> map){
map.put("testRequestScope","hello,map");
System.out.println(map.getClass().getName());
return "success";
}
5、使用ModelMap向request域对象共享数据
//使用ModelMap向request域对象共享数据
@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap){
modelMap.addAttribute("testRequestScope","hello,ModelMap");
System.out.println(modelMap.getClass().getName());
return "success";
}
6、Model、ModelMap、Map的关系
Model、ModelMap、Map类型的参数其实本质上都是 BindingAwareModelMap 类型的
public interface Model{}
public class ModelMap extends LinkedHashMap<String, Object> {}
public class ExtendedModelMap extends ModelMap implements Model {}
public class BindingAwareModelMap extends ExtendedModelMap {}
7、向session域共享数据
//使用servletAPI向session域对象共享数据
@RequestMapping("/testSession")
public String testSession(HttpSession session){
session.setAttribute("testSessionScope","hello,Session");
return "success";
}
8、向application域共享数据
//使用servletAPI向application域对象共享数据
@RequestMapping("/testApplication")
public String testApplication(HttpSession session){
ServletContext application = session.getServletContext();
application.setAttribute("testApplicationScope","hello,Application");
return "success";
}
8、SpringMVC的视图
SpringMVC中的视图是View接口,视图的作用渲染数据,将模型Model中的数据展示给用户
SpringMVC视图的种类很多,默认有转发视图和重定向视图
当工程引入jstl的依赖,转发视图会自动转换为JstlView
若使用的视图技术为Thymeleaf,在SpringMVC的配置文件中配置了Thymeleaf的视图解析器,由此视图解析器解析之后所得到的是ThymeleafView
1、ThymeleafView
当控制器方法中所设置的视图名称没有任何前缀时,此时的视图名称会被SpringMVC配置文件中所配置的视图解析器解析,视图名称拼接视图前缀和视图后缀所得到的最终路径,会通过转发的方式实现跳转
@RequestMapping("/testThymeleafView")
public String testThymeleafView(){
return "success";
}
2、转发视图
SpringMVC中默认的转发视图是InternalResourceView
SpringMVC中创建转发视图的情况:
当控制器方法中所设置的视图名称以"forward:“为前缀时,创建InternalResourceView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将**前缀"forward:"去掉,剩余部分作为最终路径通过转发的方式实现跳转**
例如"forward:/”,“forward:/employee”
/* 1.如果转发不符合视图解析器的规则,需要添加forward前缀进行转发
2.地址栏显示的是testForward
但是页面显示的是success这个页面
因为服务器内部转发不会改变地址栏:浏览器只发送一次请求
*/
@RequestMapping("/testForward")
public String testForward(){
return "forward:/testThymeleafView";
}
3、重定向视图
SpringMVC中默认的重定向视图是RedirectView
当控制器方法中所设置的视图名称以=="redirect:“为前缀时,创建RedirectView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"redirect:"去掉,剩余部分作为最终路径通过重定向==的方式实现跳转
例如"redirect:/”,“redirect:/employee”
/* 1.重定向
2.地址栏显示的是testThymeleafView
页面显示的是success这个页面
因为重定向的话浏览器发送两次请求:第一次请求是RedirectView , 第二次请求是thymeleafView
*/
@RequestMapping("/testRedirect")
public String testRedirect(){
return "redirect:/testThymeleafView";
}
注:重定向视图在解析时,会先将redirect:前缀去掉,然后会判断剩余部分是否以 / 开头,若是则会自动拼接上下文路径
4、视图控制器view-controller
当控制器方法中,仅仅用来实现页面跳转,即只需要设置视图名称时,可以将处理器方法使用view-controller标签进行表示
<!--
path:设置处理的请求地址
view-name:设置请求地址所对应的视图名称
-->
<mvc:view-controller path="/testView" view-name="success"></mvc:view-controller>
注:当SpringMVC中设置任何一个view-controller时,其他控制器中的请求映射将全部失效,此时需要在SpringMVC的核心配置文件中设置开启mvc注解驱动的标签:<mvc:annotation-driven />
// @RequestMapping("/")
// public String index(){
// return "index";
// }
5 转发和重定向区别
1 转发:一次请求:其实也是两次请求:一次是浏览器向服务器发送请求,第二次是服务器内部进行请求的发送(地址栏地址不会改变),一般说一次请求(即浏览器发送一次请求)
2 重定向:两次请求:第一次是浏览器向服务器发送的请求(访向servlet),第二次是访问重定向的地址(浏览器发送两次请求)-----地址栏是第二次重定向之后的地址
3 转发可以获取请求域中的数据,而重定向不可以获取请求域中的数据:因为转发是一次请求,用到的request对象是同一个,重定向是两次请求,用到了两个request对象
转发可以访问WEB-INF下的资源,而重定向不可以,因为WEB-INF下面的资源具有安全性,隐私性,只能通过服务器内部来访问,不可以通过浏览器来进行访问
转发不可以跨域(转发发生在服务器内部,所以只能访问服务器内部的资源,但是重定向因为是浏览器发送的两次请求,所以可以访问任何资源,比如重定向到百度这些其他的资源页面),重定向可以进行跨域
“redirect:/”:指的是重定向到首页
“redirect:/testHello”:指重定向到一个请求
如果写的是重定向到某一个页面:因为现在的页面必须经过thymeleaf解析,所以只能通过转发进行访问(页面在WEB-INF下),那么重定向访问不了这个页面,只能是重定向到一个请求,而不是一个具体的页面
9、RESTful
1、RESTful简介
REST:Representational State Transfer,表现层资源状态转移。
a>资源
资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成。每个资源是服务器上一个可命名的抽象概念。因为资源是一个抽象的概念,所以它不仅仅能代表服务器文件系统中的一个文件、数据库中的一张表等等具体的东西,可以将资源设计的要多抽象有多抽象,只要想象力允许而且客户端应用开发者能够理解。
与面向对象设计类似,资源是以名词为核心来组织的,首先关注的是名词。一个资源可以由一个或多个URI来标识。URI既是资源的名称,也是资源在Web上的地址。对某个资源感兴趣的客户端应用,可以通过资源的URI与其进行交互。
b>资源的表述
资源的表述是一段对于资源在某个特定时刻的状态的描述。可以在客户端-服务器端之间转移(交换)。资源的表述可以有多种格式,例如HTML/XML/JSON/纯文本/图片/视频/音频等等。资源的表述格式可以通过协商机制来确定。请求-响应方向的表述通常使用不同的格式。
c>状态转移
状态转移说的是:在客户端和服务器端之间转移(transfer)代表资源状态的表述。通过转移和操作资源的表述,来间接实现操作资源的目的。
2、RESTful的实现
具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。
它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。
REST 风格提倡 URL 地址使用统一的风格设计,从前到后各个单词使用斜杠分开,不使用问号键值对方式携带请求参数,而是将要发送给服务器的数据作为== URL 地址==的一部分,以保证整体风格的一致性。
操作 | 传统方式 | REST风格 |
---|---|---|
查询操作 | getUserById?id=1 | user/1–>get请求方式 |
保存操作 | saveUser | user–>post请求方式 |
删除操作 | deleteUser?id=1 | user/1–>delete请求方式 |
更新操作 | updateUser | user–>put请求方式 |
3、HiddenHttpMethodFilter
由于浏览器只支持发送get和post方式的请求,那么该如何发送put和delete请求呢?
SpringMVC 提供了 HiddenHttpMethodFilter 帮助我们将 POST 请求转换为 DELETE 或 PUT 请求
HiddenHttpMethodFilter 处理put和delete请求的条件:
a>当前请求的请求方式必须为post
b>当前请求必须 传输请求参数 _method
满足以上条件,HiddenHttpMethodFilter 过滤器就会将当前请求的请求方式转换为请求参数==_method==的值,因此请求参数_method的值才是最终的请求方式
在web.xml中注册HiddenHttpMethodFilter
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
举例:
<form th:action="@{/user}" method="post"> <input type="hidden" name="_method" value="PUT"/> 用户名:<input type="text" name="username"/><br> 密码:<input type="password" name="password"/><br> <input type="submit" value="修改"/><br> </form>
在表单中利用隐藏域进行请求方式的转变:
注:目前为止,SpringMVC中提供了两个过滤器:CharacterEncodingFilter和HiddenHttpMethodFilter
在web.xml中注册时,必须先注册CharacterEncodingFilter,再注册HiddenHttpMethodFilter
原因:在 CharacterEncodingFilter 中通过 request.setCharacterEncoding(encoding) 方法设置字符集的==request.setCharacterEncoding(encoding) ==方法要求前面不能有任何获取请求参数的操作
而 HiddenHttpMethodFilter 恰恰有一个获取请求方式的操作:String paramValue = request.getParameter(this.methodParam);
10、 resttful案例
11、HttpMessageConverter
HttpMessageConverter,报文信息转换器,将请求报文转换为Java对象,或将Java对象转换为响应报文
HttpMessageConverter提供了两个注解和两个类型:
@RequestBody,@ResponseBody,
RequestEntity,ResponseEntity
1、@RequestBody
@RequestBody可以获取请求体,需要在控制器方法设置一个形参,使用@RequestBody进行标识,当前请求的请求体就会为当前注解所标识的形参赋值
<form th:action="@{/testRequestBody}" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit">
</form>
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody String requestBody){
System.out.println("requestBody:"+requestBody);
return "success";
}
输出结果:
requestBody:username=admin&password=123456
2、RequestEntity
RequestEntity封装请求报文的一种类型,需要在控制器方法的形参中设置该类型的形参,当前请求的请求报文就会**赋值给该形参,可以通过getHeaders()**获取请求头信息,通过 getBody() 获取请求体信息
@RequestMapping("/testRequestEntity")
public String testRequestEntity(RequestEntity<String> requestEntity){
System.out.println("requestHeader:"+requestEntity.getHeaders());
System.out.println("requestBody:"+requestEntity.getBody());
return "success";
}
输出结果:requestHeader:[host:“localhost:8080”, connection:“keep-alive”, content-length:“27”, cache-control:“max-age=0”, sec-ch-ua:“” Not A;Brand";v=“99”, “Chromium”;v=“90”, “Google Chrome”;v=“90"”, sec-ch-ua-mobile:“?0”, upgrade-insecure-requests:“1”, origin:“http://localhost:8080”, user-agent:“Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36”]
requestBody:username=admin&password=123
3、@ResponseBody
@ResponseBody用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器
@RequestMapping("/testResponseBody")
@ResponseBody //不加这个注解,则success返回值作为页面出现;加上这个注解,则success返回值作为响应浏览器的响应体
public String testResponseBody(){
return "success";
}
结果:浏览器页面显示success
4、SpringMVC处理json
@ResponseBody处理json的步骤:
a>导入jackson的依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</version>
</dependency>
b>在SpringMVC的核心配置文件中开启mvc的注解驱动,此时在HandlerAdaptor中会自动装配一个消息转换器:
MappingJackson2HttpMessageConverter,可以将响应到浏览器的Java对象转换为Json格式的字符串
<!--开启mvc的注解驱动-->
<mvc:annotation-driven>
<mvc:message-converters>
<!-- 处理响应中文内容乱码 -->
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="defaultCharset" value="UTF-8" />
<property name="supportedMediaTypes">
<list>
<value>text/html</value>
<value>application/json</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
c>在处理器方法上使用**@ResponseBody**注解进行标识
d>将Java对象直接作为控制器方法的返回值返回,就会自动转换为Json格式的字符串
@RequestMapping("/testResponseUser")
@ResponseBody
public User testResponseUser(){
return new User(1001,"admin","123456",23,"男");
}
浏览器的页面中展示的结果:
{“id”:1001,“username”:“admin”,“password”:“123456”,“age”:23,“sex”:“男”}
注意:如果最外层是 [ ] : 表示是json数组
如果最外层是 { } : 表示是json对象
5、SpringMVC处理ajax
a>请求超链接:
<div id="app">
<a th:href="@{/testAjax}" @click="testAjax">testAjax</a><br>
</div>
b>通过vue和axios处理点击事件:
<script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
<script type="text/javascript" th:src="@{/static/js/axios.min.js}"></script>
<script type="text/javascript">
var vue = new Vue({
el:"#app",
methods:{
testAjax:function (event) {
axios({
method:"post",
url:event.target.href,
params:{
username:"admin",
password:"123456"
}
}).then(function (response) {
alert(response.data);
});
event.preventDefault();
}
}
});
</script>
c>控制器方法:
@RequestMapping("/testAjax")
@ResponseBody
public String testAjax(String username, String password){
System.out.println("username:"+username+",password:"+password);
return "hello,ajax";
}
6、@RestController注解
@RestController注解是springMVC提供的一个复合注解,标识在控制器的类上,就相当于为类添加了==@Controller注解==,并且为其中的每个方法添加了==@ResponseBody注解==
7、ResponseEntity
ResponseEntity用于控制器方法的返回值类型,该控制器方法的返回值就是响应到浏览器的响应报文
12、 文件上传和下载
1、文件下载
使用ResponseEntity实现下载文件的功能
@RequestMapping("/testDown") public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException { //获取ServletContext对象 ServletContext servletContext = session.getServletContext(); //获取服务器中文件的真实路径 String realPath = servletContext.getRealPath("/static/img/1.jpg"); //创建输入流 InputStream is = new FileInputStream(realPath); //创建字节数组 byte[] bytes = new byte[is.available()];//获取输入流文件对应的所有字节 //将流读到字节数组中 is.read(bytes); //创建HttpHeaders对象设置响应头信息 MultiValueMap<String, String> headers = new HttpHeaders(); //设置要下载方式以及下载文件的名字 headers.add("Content-Disposition", "attachment;filename=1.jpg"); //设置响应状态码 HttpStatus statusCode = HttpStatus.OK; //创建ResponseEntity对象 ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode); //关闭输入流 is.close(); return responseEntity; }
2、文件上传
文件上传要求form表单的请求方式必须为post,并且添加属性enctype="multipart/form-data"
SpringMVC中将上传的文件封装到MultipartFile对象中,通过此对象可以获取文件相关信息
上传步骤:
a>添加依赖:
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency>
b>在SpringMVC的配置文件中添加配置:
<!--必须通过文件解析器的解析才能将文件转换为MultipartFile对象--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
c>控制器方法:
@RequestMapping("/testUp")
public String testUp(MultipartFile photo,HttpSession session) throws IOException {
//获取上传的文件的文件名
String fileName = photo.getOriginalFilename();
//获取上传的文件的后缀名
String suffixName = fileName.substring(fileName.lastIndexOf("."));
//将UUID作为文件名,并且将其中的“-” 替换为 “”(替换不是必要的操作)
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
//将uuid和后缀名拼接后的结果作为最终的文件名
fileName = uuid + suffixName;
//通过ServletContext获取服务器中photo目录的路径
ServletContext servletContext = session.getServletContext();
String photoPath = servletContext.getRealPath("photo");
File file = new File(photoPath);
//判断photoPath所对应路径是否存在
if(!file.exists()){
//若不存在,则创建目录
file.mkdir();
}
String finalPath = photoPath + File.separator + fileName;
//上传文件
photo.transferTo(new File(finalPath));
return "success";
}
13 、拦截器
1、拦截器的配置
SpringMVC中的拦截器用于拦截控制器方法的执行
SpringMVC中的拦截器需要实现HandlerInterceptor
SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置:
<bean class="com.atguigu.interceptor.FirstInterceptor"></bean>
<ref bean="firstInterceptor"></ref>
<!-- 以上两种配置方式都是对DispatcherServlet所处理的所有的请求进行拦截 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/testRequestEntity"/>
<ref bean="firstInterceptor"></ref>
</mvc:interceptor>
<!--
以上配置方式可以通过ref或bean标签设置拦截器,通过mvc:mapping设置需要拦截的请求,通过mvc:exclude-mapping设置需要排除的请求,即不需要拦截的请求
-->
2、拦截器的三个抽象方法
SpringMVC中的拦截器有三个抽象方法:
preHandle:控制器方法执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返回true为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法
postHandle:控制器方法执行之后执行postHandle()
afterComplation:处理完视图和模型数据,渲染视图完毕之后执行afterComplation()
3、多个拦截器的执行顺序
a>若每个拦截器的preHandle()都返回true
此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关:
preHandle()会按照配置的顺序执行,而postHandle()和afterComplation()会按照配置的反序执行
b>若某个拦截器的preHandle()返回了false
preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false的拦截器之前的拦截器的afterComplation()会执行
14、异常处理器
1、基于配置的异常处理
SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口:HandlerExceptionResolver
HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolver和SimpleMappingExceptionResolver
SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResolver,使用方式:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <!-- properties的键表示处理器方法执行过程中出现的异常 properties的值表示若出现指定异常时,设置一个新的视图名称,跳转到指定页面 --> <prop key="java.lang.ArithmeticException">error</prop> </props> </property> <!-- exceptionAttribute属性设置一个属性名,将出现的异常信息在请求域中进行共享 --> <property name="exceptionAttribute" value="ex"></property> </bean>
2、基于注解的异常处理
//@ControllerAdvice将当前类标识为异常处理的组件
@ControllerAdvice
public class ExceptionController {
//@ExceptionHandler用于设置所标识方法处理的异常
@ExceptionHandler(ArithmeticException.class)
//ex表示当前请求处理中出现的异常对象
public String handleArithmeticException(Exception ex, Model model){
model.addAttribute("ex", ex);
return "error";
}
}
15、注解配置SpringMVC
使用配置类和注解代替web.xml和SpringMVC配置文件的功能
1、创建初始化类,代替web.xml
在Servlet3.0环境中,容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类,如果找到的话就用它来配置Servlet容器。Spring提供了这个接口的实现,名为SpringServletContainerInitializer,这个类反过来又会查找实现WebApplicationInitializer的类并将配置的任务交给它们来完成。
Spring3.2引入了一个便利的WebApplicationInitializer基础实现,名为AbstractAnnotationConfigDispatcherServletInitializer,当我们的类扩展了AbstractAnnotationConfigDispatcherServletInitializer并将其部署到Servlet3.0容器的时候,容器会自动发现它,并用它来配置Servlet上下文。
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* 指定spring的配置类
* @return
*/
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
/**
* 指定SpringMVC的配置类
* @return
*/
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
/**
* 指定DispatcherServlet的映射规则,即url-pattern
* @return
*/
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
/**
* 添加过滤器
* @return
*/
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
encodingFilter.setEncoding("UTF-8");
encodingFilter.setForceRequestEncoding(true);
HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
return new Filter[]{encodingFilter, hiddenHttpMethodFilter};
}
}
2、创建SpringConfig配置类,代替spring的配置文件
@Configuration
public class SpringConfig {
//ssm整合之后,spring的配置信息写在此类中
}
3、创建WebConfig配置类,代替SpringMVC的配置文件(springMVC.xml)
/** * 代替SpringMVC的配置文件:springMVC.xml * 1、扫描组件 2、视图解析器 3、view-controller 4、default-servlet-handler * 5、mvc注解驱动 6、文件上传解析器 7、异常处理 8、拦截器 */ //将当前类标识为一个配置类 @Configuration //1、扫描组件 @ComponentScan("com.atguigu.mvc.controller") //5、mvc注解驱动 @EnableWebMvc public class WebConfig implements WebMvcConfigurer {
<span class="token comment">//4、default-servlet-handler</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">configureDefaultServletHandling</span><span class="token punctuation">(</span><span class="token class-name">DefaultServletHandlerConfigurer</span> configurer<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> configurer<span class="token punctuation">.</span><span class="token function">enable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//8、拦截器</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">addInterceptors</span><span class="token punctuation">(</span><span class="token class-name">InterceptorRegistry</span> registry<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token class-name">TestInterceptor</span> testInterceptor <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TestInterceptor</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> registry<span class="token punctuation">.</span><span class="token function">addInterceptor</span><span class="token punctuation">(</span>testInterceptor<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addPathPatterns</span><span class="token punctuation">(</span><span class="token string">"/**"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//3、view-controller</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">addViewControllers</span><span class="token punctuation">(</span><span class="token class-name">ViewControllerRegistry</span> registry<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> registry<span class="token punctuation">.</span><span class="token function">addViewController</span><span class="token punctuation">(</span><span class="token string">"/hello"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setViewName</span><span class="token punctuation">(</span><span class="token string">"hello"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//6、文件上传解析器</span> <span class="token annotation punctuation">@Bean</span> <span class="token keyword">public</span> <span class="token class-name">MultipartResolver</span> <span class="token function">multipartResolver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> <span class="token class-name">CommonsMultipartResolver</span> commonsMultipartResolver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CommonsMultipartResolver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> commonsMultipartResolver<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//7、异常处理</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">configureHandlerExceptionResolvers</span><span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">HandlerExceptionResolver</span><span class="token punctuation">></span></span> resolvers<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token class-name">SimpleMappingExceptionResolver</span> exceptionResolver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SimpleMappingExceptionResolver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">Properties</span> prop <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Properties</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> prop<span class="token punctuation">.</span><span class="token function">setProperty</span><span class="token punctuation">(</span><span class="token string">"java.lang.ArithmeticException"</span><span class="token punctuation">,</span> <span class="token string">"error"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> exceptionResolver<span class="token punctuation">.</span><span class="token function">setExceptionMappings</span><span class="token punctuation">(</span>prop<span class="token punctuation">)</span><span class="token punctuation">;</span> exceptionResolver<span class="token punctuation">.</span><span class="token function">setExceptionAttribute</span><span class="token punctuation">(</span><span class="token string">"exception"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> resolvers<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>exceptionResolver<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//配置生成模板解析器</span> <span class="token annotation punctuation">@Bean</span> <span class="token keyword">public</span> <span class="token class-name">ITemplateResolver</span> <span class="token function">templateResolver</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token class-name">WebApplicationContext</span> webApplicationContext <span class="token operator">=</span> <span class="token class-name">ContextLoader</span><span class="token punctuation">.</span><span class="token function">getCurrentWebApplicationContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过WebApplicationContext 的方法获得</span> <span class="token class-name">ServletContextTemplateResolver</span> templateResolver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ServletContextTemplateResolver</span><span class="token punctuation">(</span> webApplicationContext<span class="token punctuation">.</span><span class="token function">getServletContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> templateResolver<span class="token punctuation">.</span><span class="token function">setPrefix</span><span class="token punctuation">(</span><span class="token string">"/WEB-INF/templates/"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> templateResolver<span class="token punctuation">.</span><span class="token function">setSuffix</span><span class="token punctuation">(</span><span class="token string">".html"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> templateResolver<span class="token punctuation">.</span><span class="token function">setCharacterEncoding</span><span class="token punctuation">(</span><span class="token string">"UTF-8"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> templateResolver<span class="token punctuation">.</span><span class="token function">setTemplateMode</span><span class="token punctuation">(</span><span class="token class-name">TemplateMode</span><span class="token punctuation">.</span>HTML<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> templateResolver<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//生成模板引擎并为模板引擎注入模板解析器</span> <span class="token annotation punctuation">@Bean</span> <span class="token keyword">public</span> <span class="token class-name">SpringTemplateEngine</span> <span class="token function">templateEngine</span><span class="token punctuation">(</span><span class="token class-name">ITemplateResolver</span> templateResolver<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token class-name">SpringTemplateEngine</span> templateEngine <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SpringTemplateEngine</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> templateEngine<span class="token punctuation">.</span><span class="token function">setTemplateResolver</span><span class="token punctuation">(</span>templateResolver<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> templateEngine<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//生成视图解析器并未解析器注入模板引擎</span> <span class="token annotation punctuation">@Bean</span> <span class="token keyword">public</span> <span class="token class-name">ViewResolver</span> <span class="token function">viewResolver</span><span class="token punctuation">(</span><span class="token class-name">SpringTemplateEngine</span> templateEngine<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token class-name">ThymeleafViewResolver</span> viewResolver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ThymeleafViewResolver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> viewResolver<span class="token punctuation">.</span><span class="token function">setCharacterEncoding</span><span class="token punctuation">(</span><span class="token string">"UTF-8"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> viewResolver<span class="token punctuation">.</span><span class="token function">setTemplateEngine</span><span class="token punctuation">(</span>templateEngine<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> viewResolver<span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
4、测试功能
@RequestMapping("/")
public String index(){
return "index";
}
16、SpringMVC执行流程
1、SpringMVC常用组件
DispatcherServlet:前端控制器,不需要工程师开发,由框架提供
作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求
HandlerMapping:处理器映射器,不需要工程师开发,由框架提供 其实就是==@RequestMapping==
作用:根据请求的url、method等信息查找Handler,即控制器方法
Handler:处理器,需要工程师开发 其实就是控制器
作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理
HandlerAdapter:处理器适配器,不需要工程师开发,由框架提供
作用:通过HandlerAdapter对处理器(控制器方法)进行执行
ViewResolver:视图解析器,不需要工程师开发,由框架提供
作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、RedirectView
View:视图
作用:将模型数据通过页面展示给用户
2、DispatcherServlet初始化过程
DispatcherServlet 本质上是一个 Servlet,所以天然的遵循 Servlet 的生命周期。所以宏观上是 Servlet 生命周期来进行调度。
a>初始化WebApplicationContext
所在类:org.springframework.web.servlet.FrameworkServlet
protected WebApplicationContext initWebApplicationContext() { WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null;
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>webApplicationContext <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">// A context instance was injected at construction time -> use it</span> wac <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>webApplicationContext<span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>wac <span class="token keyword">instanceof</span> <span class="token class-name">ConfigurableWebApplicationContext</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token class-name">ConfigurableWebApplicationContext</span> cwac <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">ConfigurableWebApplicationContext</span><span class="token punctuation">)</span> wac<span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>cwac<span class="token punctuation">.</span><span class="token function">isActive</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">// The context has not yet been refreshed -> provide services such as</span> <span class="token comment">// setting the parent context, setting the application context id, etc</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>cwac<span class="token punctuation">.</span><span class="token function">getParent</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">// The context instance was injected without an explicit parent -> set</span> <span class="token comment">// the root application context (if any; may be null) as the parent</span> cwac<span class="token punctuation">.</span><span class="token function">setParent</span><span class="token punctuation">(</span>rootContext<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">configureAndRefreshWebApplicationContext</span><span class="token punctuation">(</span>cwac<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>wac <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">// No context instance was injected at construction time -> see if one</span> <span class="token comment">// has been registered in the servlet context. If one exists, it is assumed</span> <span class="token comment">// that the parent context (if any) has already been set and that the</span> <span class="token comment">// user has performed any initialization such as setting the context id</span> wac <span class="token operator">=</span> <span class="token function">findWebApplicationContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>wac <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">// No context instance is defined for this servlet -> create a local one</span> <span class="token comment">// 创建WebApplicationContext</span> wac <span class="token operator">=</span> <span class="token function">createWebApplicationContext</span><span class="token punctuation">(</span>rootContext<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">this</span><span class="token punctuation">.</span>refreshEventReceived<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">// Either the context is not a ConfigurableApplicationContext with refresh</span> <span class="token comment">// support or the context injected at construction time had already been</span> <span class="token comment">// refreshed -> trigger initial onRefresh manually here.</span> <span class="token keyword">synchronized</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>onRefreshMonitor<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">// 刷新WebApplicationContext</span> <span class="token function">onRefresh</span><span class="token punctuation">(</span>wac<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>publishContext<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">// Publish the context as a servlet context attribute.</span> <span class="token comment">// 将IOC容器在应用域共享</span> <span class="token class-name">String</span> attrName <span class="token operator">=</span> <span class="token function">getServletContextAttributeName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">getServletContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span>attrName<span class="token punctuation">,</span> wac<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> wac<span class="token punctuation">;</span>
}
b>创建WebApplicationContext
所在类:org.springframework.web.servlet.FrameworkServlet
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) { Class<?> contextClass = getContextClass(); if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { throw new ApplicationContextException( "Fatal initialization error in servlet with name '" + getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext"); } // 通过反射创建 IOC 容器对象 ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); wac.setEnvironment(getEnvironment()); // 设置父容器 wac.setParent(parent); String configLocation = getContextConfigLocation(); if (configLocation != null) { wac.setConfigLocation(configLocation); } configureAndRefreshWebApplicationContext(wac); return wac; }
c>DispatcherServlet初始化策略
FrameworkServlet创建WebApplicationContext后,刷新容器,调用onRefresh(wac),此方法在DispatcherServlet中进行了重写,调用了**initStrategies(context)**方法,初始化策略,即初始化DispatcherServlet的各个组件
所在类:org.springframework.web.servlet.DispatcherServlet
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
3、DispatcherServlet调用组件处理请求
a>processRequest()
FrameworkServlet重写HttpServlet中的service()和doXxx(),这些方法中调用了processRequest(request, response)
所在类:org.springframework.web.servlet.FrameworkServlet
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
initContextHolders(request, localeContext, requestAttributes);
try {
// 执行服务,doService()是一个抽象方法,在DispatcherServlet中进行了重写
doService(request, response);
}
catch (ServletException | IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
logResult(request, response, failureCause, asyncManager);
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
b>doService()
所在类:org.springframework.web.servlet.DispatcherServlet
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
logRequest(request);
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
if (this.flashMapManager != null) {
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}
RequestPath requestPath = null;
if (this.parseRequestPath && !ServletRequestPathUtils.hasParsedRequestPath(request)) {
requestPath = ServletRequestPathUtils.parseAndCache(request);
}
try {
// 处理请求和响应
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
if (requestPath != null) {
ServletRequestPathUtils.clearParsedRequestPath(request);
}
}
}
c>doDispatch()
所在类:org.springframework.web.servlet.DispatcherServlet
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // Determine handler for the current request. /* mappedHandler:调用链 包含handler、interceptorList、interceptorIndex handler:浏览器发送的请求所匹配的控制器方法 interceptorList:处理控制器方法的所有拦截器集合 interceptorIndex:拦截器索引,控制拦截器afterCompletion()的执行 */ mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. // 通过控制器方法创建相应的处理器适配器,调用所对应的控制器方法 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } }
<span class="token comment">// 调用拦截器的preHandle()</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>mappedHandler<span class="token punctuation">.</span><span class="token function">applyPreHandle</span><span class="token punctuation">(</span>processedRequest<span class="token punctuation">,</span> response<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
// Actually invoke the handler.
// 由处理器适配器调用具体的控制器方法,最终获得ModelAndView对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 调用拦截器的postHandle()
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 后续处理:处理模型数据和渲染视图
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
d>processDispatchResult()
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
// 处理模型数据和渲染视图
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
// Exception (if any) is already handled..
// 调用拦截器的afterCompletion()
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
4、SpringMVC的执行流程
- 用户向服务器发送请求,请求被SpringMVC 前端控制器 DispatcherServlet捕获。
- DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI),
UPI 和 UPL的区别
判断请求URI对应的映射:
a) 不存在
i. 再判断是否配置了mvc:default-servlet-handler
ii. 如果没配置,则控制台报映射查找不到,客户端展示404错误
(当报此错误时,去target下面看资源是否成功部署在服务器中;如果没有成功部署到服务器上,也会找不相应的页面资源)
此时是DispatcherServlet 报 404找不到
iii. 如果有配置,则访问目标资源(一般为静态资源,如:JS,CSS,HTML),找不到客户端也会展示404错误
此时是DefaultServletHttpRequsetHandler 报404找不到
b) 存在则执行下面的流程
3) 根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器,也即是:handler、interceptorList、interceptorIndex),最后以HandlerExecutionChain执行链对象的形式返回。
- DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter(例如RequestMappingHandlerAdapter)。
- 如果成功获得HandlerAdapter,此时将开始执行拦截器的preHandler(…)方法【正向】
- 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
a) HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
b) 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
c) 数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
d) 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
- Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象。
- 此时将开始执行拦截器的postHandle(…)方法【逆向】。
- 根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver进行视图解析,根据Model和View,来渲染视图。
- 渲染视图完毕执行拦截器的afterCompletion(…)方法【逆向】。
- 将渲染结果返回给客户端。
4 springmvc 注解
注解 | 功能 |
---|---|
@RequestMapping | 处理请求和控制器方法之间的映射关系 |
@GetMapping | 处理get请求的映射 |
@PostMapping | 处理post请求的映射 |
@PutMapping | 处理put请求的映射 |
@DeleteMapping | 处理delete请求的映射 |
@PathVariable | 将占位符所表示的数据赋值给控制器方法的形参 |
@RequestParam | 将请求参数和控制器方法的形参创建映射关系 |
@RequestHeader | 将请求头信息和控制器方法的形参创建映射关系 |
@CookieValue | 将cookie数据和控制器方法的形参创建映射关系 |
@ControllerAdvice | 将当前类标识为异常处理的组件 |
@EnableWebMvc | mvc注解驱动 |
@bean | 告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理 |
@RequestBody | 可以获取请求体,需要在控制器方法设置一个形参,使用@RequestBody进行标识,当前请求的请求体就会为当前注解所标识的形参赋值 |
@ResponseBody | 用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器 |
@RestController | 复合注解,标识在控制器的类上,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody注解 |
总结
①
浏览器发送请求,若请求地址符合前端控制器的url-pattern,该请求就会被前端控制器DispatcherServlet处理。前端控制器会读取SpringMVC的核心配置文件,通过扫描组件找到控制器,将请求地址和控制器中 @RequestMapping注解的value属性值进行匹配,若匹配成功,该注解所标识的控制器方法就是处理请求的方法。处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析,加上前缀和后缀组成视图的路径,通过Thymeleaf对视图进行渲染,最终转发到视图所对应页面。
②
报错情况
如果当前请求和RequestMapping中的任何一个value属性不匹配,报404
如果当前请求方式匹配不了,报405 请求方式不被支持
如果请求参数匹配不了,报400 传输参数不一致
请求头信息不匹配,报404
③
SpringMVC常用组件
DispatcherServlet:前端控制器,不需要工程师开发,由框架提供
作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求
HandlerMapping:处理器映射器,不需要工程师开发,由框架提供 其实就是 @RequestMapping
作用:根据请求的url、method等信息查找Handler,即控制器方法
Handler:处理器,需要工程师开发 其实就是控制器
作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理
HandlerAdapter:处理器适配器,不需要工程师开发,由框架提供
作用:通过HandlerAdapter对处理器(控制器方法)进行执行
ViewResolver:视图解析器,不需要工程师开发,由框架提供
作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、RedirectView
View:视图
作用:将模型数据通过页面展示给用户
④
SpringMVC的执行流程
- 用户向服务器发送请求,请求被SpringMVC 前端控制器 DispatcherServlet捕获。
- DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI),判断请求URI对应的映射:
a) 不存在
i. 再判断是否配置了mvc:default-servlet-handler
ii. 如果没配置,则控制台报映射查找不到,客户端展示404错误 (当报此错误时,去target下面看资源是否成功部署在服务器中;如果没有成功部署到服务器上,也会找不相应的页面资源)
此时是DispatcherServlet 报 404找不到
iii. 如果有配置,则访问目标资源(一般为静态资源,如:JS,CSS,HTML),找不到客户端也会展示404错误
此时是DefaultServletHttpRequsetHandler 报404找不到
b) 存在则执行下面的流程
- 根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器,也即是:handler、interceptorList、interceptorIndex),最后以HandlerExecutionChain执行链对象的形式返回。
- DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter(例如RequestMappingHandlerAdapter)。
- 如果成功获得HandlerAdapter,此时将开始执行拦截器的preHandler(…)方法**【正向】**
- 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
a) HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
b) 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
c) 数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
d) 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
- Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象。
- 此时将开始执行拦截器的postHandle(…)方法**【逆向】**。
- 根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver进行视图解析,根据Model和View,来渲染视图。
- 渲染视图完毕执行拦截器的afterCompletion(…)方法【逆向】。
- 将渲染结果返回给客户端
四 、MyBatis
1 简介
1.1 特性
MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架
MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集
MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录
MyBatis 是一个 半自动的ORM(Object Relation Mapping)框架
2 搭建MyBatis环境
1.开发环境
IDE:idea 2019.2
构建工具:maven 3.5.4
MySQL版本:MySQL 5.7
MyBatis版本:MyBatis 3.5.7
2.创建maven工程
打包方式:jar <packaging>jar</packaging>
引入依赖
<dependencies>
<!-- Mybatis核心 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!-- junit测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.3</version>
</dependency>
</dependencies>
3.创建MyBatis的核心配置文件
习惯上命名为mybatis-config.xml,这个文件名仅仅只是建议,并非强制要求。将来整合Spring之后,这个配置文件可以省略,所以大家操作时可以直接复制、粘贴。
核心配置文件主要用于配置连接数据库的环境以及MyBatis的全局配置信息
核心配置文件存放的位置是src/main/resources目录下
<?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>
<!--设置连接数据库的环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/MyBatis"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<mapper resource="mappers/UserMapper.xml"/>
</mappers>
</configuration>
4.创建mapper接口
MyBatis中的mapper接口相当于以前的dao。但是区别在于,mapper仅仅是接口,我们不需要提供实现类
package com.atguigu.mybatis.mapper;
public interface UserMapper {
/**
* 添加用户信息
*/
int insertUser();
}
5.创建MyBatis的映射文件
相关概念:ORM(Object Relationship Mapping)对象关系映射。
对象:Java的实体类对象
关系:关系型数据库
映射:二者之间的对应关系
Java概念 | 数据库概念 |
---|---|
类 | 表 |
属性 | 字段/列 |
对象 | 记录/行 |
映射文件的命名规则
表所对应的实体类的类名+Mapper.xml
例如:表t_user,映射的实体类为User,所对应的映射文件为UserMapper.xml ==
因此一个映射文件==对应一个实体类,对应一张表的操作
MyBatis映射文件用于编写SQL,访问以及操作表中的数据
MyBatis映射文件存放的位置是src/main/resources/mappers目录下
MyBatis中可以面向接口操作数据,要保证两个一致
mapper接口的全类名和映射文件的命名空间(namespace)保持一致
mapper接口中方法的方法名和映射文件中编写SQL的标签的id属性保持一致
<?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.atguigu.mybatis.mapper.UserMapper">
<!--int insertUser();-->
<insert id="insertUser">
insert into t_user values(null,'张三','123',23,'女')
</insert>
</mapper>
6.通过junit测试功能
SqlSession:代表Java程序和数据库之间的会话。(HttpSession是Java程序和浏览器之间的会话)
SqlSessionFactory:是“生产”SqlSession的“工厂”
工厂模式:如果创建某一个对象,使用的过程基本固定,那么我们就可以把创建这个对象的相关代码封装到一个“工厂类”中,以后都使用这个工厂类来“生产”我们需要的对象
public class UserMapperTest {
@Test
public void testInsertUser() throws IOException {
//读取MyBatis的核心配置文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//获取SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//通过核心配置文件所对应的字节输入流创建工厂类SqlSessionFactory,生产SqlSession对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
//获取sqlSession,此时通过SqlSession对象所操作的sql都必须手动提交或回滚事务
//SqlSession sqlSession = sqlSessionFactory.openSession();
//创建SqlSession对象,此时通过SqlSession对象所操作的sql都会自动提交
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//通过代理模式创建UserMapper接口的代理实现类对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用UserMapper接口中的方法,就可以根据UserMapper的全类名匹配元素文件,通过调用的方法名匹配映射文件中的SQL标签,并执行标签中的SQL语句
int result = userMapper.insertUser();
//提交事务
//sqlSession.commit();
System.out.println("result:" + result);
}
}
此时需要手动提交事务,如果要自动提交事务,则在获取sqlSession对象时,使用SqlSession sqlSession = sqlSessionFactory.openSession(true);,传入一个Boolean类型的参数,值为true,这样就可以自动提交
7.加入log4j日志功能
加入依赖
<!-- log4j日志 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
加入log4j的配置文件
log4j的配置文件名为log4j.xml,存放的位置是src/main/resources目录下
日志的级别:FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试) 从左到右打印的内容越来越详细
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<param name="Encoding" value="UTF-8" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
</layout>
</appender>
<logger name="java.sql">
<level value="debug" />
</logger>
<logger name="org.apache.ibatis">
<level value="info" />
</logger>
<root>
<level value="debug" />
<appender-ref ref="STDOUT" />
</root>
</log4j:configuration>
3 核心配置文件详解
4 MyBatis的增删改查
添加
<!--int insertUser();-->
<insert id="insertUser">
insert into t_user values(null,'admin','123456',23,'男','123456@qq.com')
</insert>
删除
<!--void deleteUser();-->
<span class="token operator"><</span>delete id<span class="token operator">=</span><span class="token string">"deleteUser"</span><span class="token operator">></span> delete from t_user where id <span class="token operator">=</span> <span class="token number">2</span> <span class="token operator"><</span><span class="token operator">/</span>delete<span class="token operator">></span>
修改
<!--void updateUser();-->
<update id="updateUser">
update t_user set username = '张三' where id = 1
</update>
查询一个实体类对象
<!--User getUserById();-->
<select id="getUserById" resultType="com.atguigu.mybatis.pojo.User">
select * from t_user where id = 1
</select>
查询集合
<!--List<User> getAllUser();-->
<select id="getAllUser" resultType="User">
select * from t_user
</select>
注意:
- 查询的标签select必须设置属性resultType或resultMap,用于设置实体类和数据库表的映射关系
- resultType:自动映射,用于属性名和表中字段名一致的情况
- resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况
- 当查询的数据为多条时,不能使用实体类作为返回值,只能使用集合,否则会抛出异常
TooManyResultsException
;但是若查询的数据只有一条,可以使用实体类或集合作为返回值
5 MyBatis获取参数值的两种方式(重点)
MyBatis获取参数值的两种方式: ${} 和 #{}
${} 的本质就是字符串拼接,#{} 的本质就是占位符赋值
${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;
但是==#{}==使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号
1.单个字面量类型的参数
若mapper接口中的方法参数为单个的字面量类型,
此时可以使用 ${} 和 #{} 以任意的名称(最好见名识意)获取参数的值,注意 ${} 需要手动加单引号
<!--User getUserByUsername(String username);-->
<select id="getUserByUsername" resultType="User">
select * from t_user where username = #{username}
</select>
<!--User getUserByUsername(String username);-->
<select id="getUserByUsername" resultType="User">
select * from t_user where username = '${username}'
</select>
2.多个字面量类型的参数
若mapper接口中的方法参数为多个时,此时MyBatis会自动将这些参数放在一个map集合中
- 以arg0,arg1…为键,以参数为值;
- 以param1,param2…为键,以参数为值;
因此只需要通过 ${} 和 #{} 访问map集合的键就可以获取相对应的值,注意 ${} 需要手动加单引号。
使用arg或者param都行,要注意的是,arg是从arg0开始的,param是从param1开始的
<!--User checkLogin(String username,String password);--> <select id="checkLogin" resultType="User"> select * from t_user where username = #{arg0} and password = #{arg1} </select>
<!--User checkLogin(String username,String password);-->
<select id="checkLogin" resultType="User">
select * from t_user where username = '${param1}' and password = '${param2}'
</select>
3.map集合类型的参数
若mapper接口中的方法需要的参数为多个时,此时可以手动创建map集合,将这些数据放在map中只需要通过${}和#{}访问map集合的键就可以获取相对应的值,注意 ${}需要手动加单引号
<!--User checkLoginByMap(Map<String,Object> map);-->
<select id="checkLoginByMap" resultType="User">
select * from t_user where username = #{username} and password = #{password}
</select>
@Test
public void checkLoginByMap() {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
Map<String,Object> map = new HashMap<>();
map.put("usermane","admin");
map.put("password","123456");
User user = mapper.checkLoginByMap(map);
System.out.println(user);
}
4.实体类类型的参数
若mapper接口中的方法参数为实体类对象时此时可以使用${}和#{},通过访问实体类对象中的属性名获取属性值,注意 ${}需要手动加单引号
<!--int insertUser(User user);-->
<insert id="insertUser">
insert into t_user values(null,#{username},#{password},#{age},#{sex},#{email})
</insert>
@Test
public void insertUser() {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
User user = new User(null,"Tom","123456",12,"男","123@321.com");
mapper.insertUser(user);
}
5.使用 @Param 标识参数
可以通过@Param注解标识mapper接口中的方法参数,此时,会将这些参数放在map集合中
以@Param注解的value属性值为键,以参数为值;
以param1,param2…为键,以参数为值;
只需要通过${}和#{}访问map集合的键就可以获取相对应的值,注意 ${}需要手动加单引号
<!--User CheckLoginByParam(@Param("username") String username, @Param("password") String password);-->
<select id="CheckLoginByParam" resultType="User">
select * from t_user where username = #{username} and password = #{password}
</select>
@Test
public void checkLoginByParam() {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
mapper.CheckLoginByParam("admin","123456");
}
总结
建议分成两种情况进行处理
- 实体类类型的参数
- 使用@Param标识参数
总结
建议分成两种情况进行处理
1.实体类类型的就以实体类类型进行处理
2.其他情况(单个字面量参数,多个字面量参数),都使用**@Param**注解方式来规定访问的数据的键是什么,进而就可以以参数为值进行访问(如果是传输过来的是map集合,就以键对应值的方式就行)
6 MyBatis的各种查询功能
7 自定义映射resultMap
1.resultMap处理字段和属性的映射关系
若字段名和实体类中的属性名不一致,则可以通过resultMap设置自定义映射,即使字段名和属性名一致的属性也要映射,也就是全部属性都要列出来
<resultMap id="empResultMap" type="Emp"> <!-- resultMap : 设置自定义映射关系 id : 唯一标识,不能重复 type:设置映射关系中的实体类类型 子标签: id:设置主键的映射关系 result:设置普通字段的映射关系 属性: property:设置映射关系中的属性名,必须是type属性所设置的实体类类型中的属性名 column:设置映射关系中的字段名,必须是sql语句查询出的字段名 -->
<resultMap id="empResultMap" type="Emp">
<id property="eid" column="eid"></id>
<result property="empName" column="emp_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="email" column="email"></result>
</resultMap>
<!--List<Emp> getAllEmp();-->
<select id="getAllEmp" resultMap="empResultMap">
select * from t_emp
</select>
若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则(使用_),实体类中的属性名符合Java的规则(使用驼峰)。此时也可通过以下两种方式处理字段名和实体类中的属性的映射关系
- 可以通过为字段起别名的方式,保证和实体类中的属性名保持一致
<!--List<Emp> getAllEmp();-->
<select id="getAllEmp" resultType="Emp">
select eid,emp_name empName,age,sex,email from t_emp
</select>
- 可以在MyBatis的核心配置文件中的
setting
标签中,设置一个全局配置信息mapUnderscoreToCamelCase,可以在查询表中数据时,自动将_类型的字段名转换为驼峰,例如:字段名user_name,设置了mapUnderscoreToCamelCase,此时字段名就会转换为userName。
<!--设置MyBatis的全局配置-->
<settings>
<!--将_自动映射为驼峰,emp_name:empName-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
2.多对一映射处理
查询员工信息以及员工所对应的部门信息
public class Emp {
private Integer eid;
private String empName;
private Integer age;
private String sex;
private String email;
private Dept dept;
//...构造器、get、set方法等
}
2.1 级联方式处理映射关系
<resultMap id="empAndDeptResultMapOne" type="Emp">
<id property="eid" column="eid"></id>
<result property="empName" column="emp_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="email" column="email"></result>
<result property="dept.did" column="did"></result>
<result property="dept.deptName" column="dept_name"></result>
</resultMap>
<!--Emp getEmpAndDept(@Param("eid")Integer eid);-->
<select id="getEmpAndDept" resultMap="empAndDeptResultMapOne">
select * from t_emp left join t_dept on t_emp.eid = t_dept.did where t_emp.eid = #{eid}
</select>
2.2 使用association处理映射关系
association:处理多对一的映射关系
property:需要处理多对的映射关系的属性名
javaType:该属性的类型
<!--处理多对一映射关系方式二:association-->
<resultMap id="empAndDeptResultMapTwo" type="Emp">
<id property="eid" column="eid"></id>
<result property="empName" column="emp_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="email" column="email"></result>
<!--
association:处理多对一的映射关系
property:需要处理多对的映射关系的属性名
javaType:该属性的类型
-->
<association property="dept" javaType="Dept">
<id property="did" column="did"></id>
<result property="deptName" column="dept_name"></result>
</association>
</resultMap>
<!--Emp getEmpAndDept(@Param("eid")Integer eid);-->
<select id="getEmpAndDept" resultMap="empAndDeptResultMapTwo">
select * from t_emp left join t_dept on t_emp.eid = t_dept.did where t_emp.eid = #{eid}
</select>
2.3 分步查询
1). 查询员工信息
select:设置分布查询的sql的唯一标识(namespace.SQLid或mapper接口的全类名.方法名)
column:设置分步查询的条件
//EmpMapper里的方法
/**
* 通过分步查询,员工及所对应的部门信息
* 分步查询第一步:查询员工信息
* @param
* @return com.atguigu.mybatis.pojo.Emp
* @date 2022/2/27 20:17
*/
Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid);
<resultMap id="empAndDeptByStepResultMap" type="Emp">
<id property="eid" column="eid"></id>
<result property="empName" column="emp_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="email" column="email"></result>
<!--
property:分步查询中需要处理的属性
select:设置分步查询的sql的唯一标识(namespace.SQLId 或 mapper接口的全类名.方法名)
column:设置分步查询的条件
fetchType:当开启了全局的延迟加载之后,可以通过此属性手动控制延迟加载的效果
fetchType="lazy|eager" : lazy表示延迟加载,eager表示立即加载
-->
<association property="dept"
select="com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
column="did"
fetchType="lazy"></association>
</resultMap>
<!--Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid);-->
<select id="getEmpAndDeptByStepOne" resultMap="empAndDeptByStepResultMap">
select * from t_emp where eid = #{eid}
</select>
2). 查询部门信息
//DeptMapper里的方法
/**
* 通过分步查询,员工及所对应的部门信息
* 分步查询第二步:通过did查询员工对应的部门信息
* @param
* @return com.atguigu.mybatis.pojo.Emp
* @date 2022/2/27 20:23
*/
Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);
<!--此处的resultMap仅是处理字段和属性的映射关系-->
<resultMap id="EmpAndDeptByStepTwoResultMap" type="Dept">
<id property="did" column="did"></id>
<result property="deptName" column="dept_name"></result>
</resultMap>
<!--Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);-->
<select id="getEmpAndDeptByStepTwo" resultMap="EmpAndDeptByStepTwoResultMap">
select * from t_dept where did = #{did}
</select>
3.一对多映射处理
public class Dept {
private Integer did;
private String deptName;
private List<Emp> emps;
//...构造器、get、set方法等
}
对一 对应对象(员工和部门属于多对一,那么员工中设置一个部门对象即可(即有一个属性))
对多 对应集合(部门和员工属于一对多,那么部门中设置一个集合来装员工对象即可)
3.1 collection
collection:用来处理一对多的映射关系
ofType:表示该属性对应的集合中存储的数据的类型
<resultMap id="deptAndEmpResultMap" type="Dept"> <id property="did" column="did"></id> <result property="deptName" column="dept_name"></result> <!-- collection:处理一对多的映射关系 property:一对多的属性 ofType:表示该属性所对应的集合中存储数据的类型 --> <collection property="emps" ofType="Emp"> <id property="eid" column="eid"></id> <result property="empName" column="emp_name"></result> <result property="age" column="age"></result> <result property="sex" column="sex"></result> <result property="email" column="email"></result> </collection> </resultMap>
<!--Dept getDeptAndEmp(@Param("did") Integer did);-->
<select id="getDeptAndEmp" resultMap="deptAndEmpResultMap">
select * from t_dept left join t_emp on t_dept.did = t_emp.did where t_dept.did = #{did}
</select>
3.2分步查询
1). 查询部门信息
/**
* 通过分步查询,查询部门及对应的所有员工信息
* 分步查询第一步:查询部门信息
* @param did
* @return com.atguigu.mybatis.pojo.Dept
* @date 2022/2/27 22:04
*/
Dept getDeptAndEmpByStepOne(@Param("did") Integer did);
<resultMap id="DeptAndEmpByStepOneResultMap" type="Dept">
<id property="did" column="did"></id>
<result property="deptName" column="dept_name"></result>
<collection property="emps"
select="com.atguigu.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo"
column="did"></collection>
</resultMap>
<!--Dept getDeptAndEmpByStepOne(@Param("did") Integer did);-->
<select id="getDeptAndEmpByStepOne" resultMap="DeptAndEmpByStepOneResultMap">
select * from t_dept where did = #{did}
</select>
2). 根据部门id查询部门中的所有员工
/**
* 通过分步查询,查询部门及对应的所有员工信息
* 分步查询第二步:根据部门id查询部门中的所有员工
* @param did
* @return java.util.List<com.atguigu.mybatis.pojo.Emp>
* @date 2022/2/27 22:10
*/
List<Emp> getDeptAndEmpByStepTwo(@Param("did") Integer did);
<!--List<Emp> getDeptAndEmpByStepTwo(@Param("did") Integer did);-->
<select id="getDeptAndEmpByStepTwo" resultType="Emp">
select * from t_emp where did = #{did}
</select>
4.延迟加载
分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息;
lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载
此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。
此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType=“lazy(延迟加载) |eager(立即加载)”
<settings>
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
@Test
public void getEmpAndDeptByStepOne() {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = mapper.getEmpAndDeptByStepOne(1);
System.out.println(emp.getEmpName());
}
关闭延迟加载,两条SQL语句都运行了
开启延迟加载,只运行获取emp的SQL语句
@Test
public void getEmpAndDeptByStepOne() {
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = mapper.getEmpAndDeptByStepOne(1);
System.out.println(emp.getEmpName());
System.out.println("----------------");
System.out.println(emp.getDept());
}
开启后,需要用到查询dept的时候才会调用相应的SQL语句
fetchType:当开启了全局的延迟加载之后,可以通过该属性手动控制延迟加载的效果,fetchType=“lazy(延迟加载)|eager(立即加载)”
<resultMap id="empAndDeptByStepResultMap" type="Emp">
<id property="eid" column="eid"></id>
<result property="empName" column="emp_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="email" column="email"></result>
<association property="dept"
select="com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
column="did"
fetchType="lazy"></association>
</resultMap>
总结:
8.延迟加载就是当想访问哪些信息就执行哪些SQL,不会将分步查询的第二步或者第三步等SQL语句执行
@Test
public void testGetEmpAndDeptByStep1(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = mapper.getEmpAndDeptByStepOne(3);
System.out.println(emp.getEmpName());
System.out.println("***************************");
System.out.println(emp.getDept());
}
延迟加载
立即加载
当开启了全局延迟加载之后,如果没有设置fetchType,那么默认就是 fetchType=''lazy" :延迟加载
如果没有开启全局延迟加载,那么则默认== fetchType=''eager"== :立即加载
8 动态SQL
9 MyBatis的缓存
1.MyBatis的一级缓存
一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从==数据库重新访问 ==
使一级缓存失效的四种情况:
- 不同的SqlSession对应不同的一级缓存
- 同一个SqlSession但是查询条件不同
- 同一个SqlSession两次查询期间执行了任何一次增删改操作
- 同一个SqlSession两次查询期间手动清空了缓存
2.MyBatis的二级缓存
二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取
二级缓存开启的条件
- 在核心配置文件中,设置全局配置属性
cacheEnabled="true"
,默认为true,不需要设置 - 在映射文件中设置标签
<cache />
- 二级缓存必须在SqlSession关闭或提交之后有效
- 查询的数据所转换的实体类类型必须实现序列化的接口
使二级缓存失效的情况:两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效
3.二级缓存的相关配置
在mapper配置文件中添加的cache标签可以设置一些属性
eviction属性:缓存回收策略
LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
默认的是 LRU
flushInterval属性:刷新间隔,单位毫秒
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句(增删改)时刷新
size属性:引用数目,正整数
代表缓存最多可以存储多少个对象,太大容易导致内存溢出
readOnly属性:只读,true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false
4.MyBatis缓存查询的顺序
先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用
如果二级缓存没有命中,再查询一级缓存
如果一级缓存也没有命中,则==查询数据库 ==
SqlSession关闭之后,一级缓存中的数据会写入二级缓存
5.整合第三方缓存EHCache(了解)
5.1添加依赖
<!-- Mybatis EHCache整合包 -->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.1</version>
</dependency>
<!-- slf4j日志门面的一个具体实现 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
5.2 各个jar包的功能
jar包名称 | 作用 |
---|---|
mybatis-ehcache | Mybatis和EHCache的整合包 |
ehcache | EHCache核心包 |
slf4j-api | SLF4J日志门面包 |
logback-classic | 支持SLF4J门面接口的一个具体实现 |
5.3 创建EHCache的配置文件ehcache.xml
名字必须叫ehcache.xml
<?xml version="1.0" encoding="utf-8" ?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <!-- 磁盘保存路径 --> <diskStore path="D:\atguigu\ehcache"/> <defaultCache maxElementsInMemory="1000" maxElementsOnDisk="10000000" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> </defaultCache> </ehcache>
5.4 设置二级缓存的类型
在xxxMapper.xml文件中设置二级缓存类型
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
5.5.加入logback日志
存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日志。创建logback的配置文件logback.xml,名字固定,不可改变
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
<!-- 指定日志输出的位置 -->
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- 日志输出的格式 -->
<!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 -->
<pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern>
</encoder>
</appender>
<!-- 设置全局日志级别。日志级别按顺序分别是:DEBUG、INFO、WARN、ERROR -->
<!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
<root level="DEBUG">
<!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->
<appender-ref ref="STDOUT" />
</root>
<!-- 根据特殊需求指定局部日志级别 -->
<logger name="com.atguigu.crowd.mapper" level="DEBUG"/>
</configuration>
5.6 EHCache配置文件说明
属性名 | 是否必须 | 作用 |
---|---|---|
maxElementsInMemory | 是 | 在内存中缓存的element的最大数目 |
maxElementsOnDisk | 是 | 在磁盘上缓存的element的最大数目,若是0表示无穷大 |
eternal | 是 | 设定缓存的elements是否永远不过期。 如果为true,则缓存的数据始终有效, 如果为false那么还要根据timeToIdleSeconds、timeToLiveSeconds判断 |
overflowToDisk | 是 | 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上timeToIdleSeconds |
timeToLiveSeconds | 否 | 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大 |
diskSpoolBufferSizeMB | 否 | DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区 |
diskPersistent | 否 | 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false |
diskExpiryThreadIntervalSeconds | 否 | 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s, 相应的线程会进行一次EhCache中数据的清理工作 |
memoryStoreEvictionPolicy | 否 | 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。 默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出) |
10 MyBatis的逆向工程
正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:
Java实体类
Mapper接口
Mapper映射文件
1.创建逆向工程的步骤
1.1 添加依赖和插件(添加在pom.xml)
<dependencies> <!-- MyBatis核心依赖包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.9</version> </dependency> <!-- junit测试 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> <!-- MySQL驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.27</version> </dependency> <!-- log4j日志 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies> <!-- 控制Maven在构建过程中相关配置 --> <build> <!-- 构建过程中用到的插件 --> <plugins> <!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 --> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.0</version> <!-- 插件的依赖 --> <dependencies> <!-- 逆向工程的核心依赖 --> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.2</version> </dependency> <!-- 数据库连接池 --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.2</version> </dependency> <!-- MySQL驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.27</version> </dependency> </dependencies> </plugin> </plugins> </build>
1.2 创建MyBatis的核心配置文件(一般命名为mybatis-config.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"/>
<typeAliases>
<package name=""/>
</typeAliases>
<environments default="development">
<environment id="development">
<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>
<package name=""/>
</mappers>
</configuration>
1.3创建逆向工程的配置文件
文件名必须是:generatorConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!--
targetRuntime: 执行生成的逆向工程的版本
MyBatis3Simple: 生成基本的CRUD(清新简洁版)
MyBatis3: 生成带条件的CRUD(奢华尊享版)
-->
<context id="DB2Tables" targetRuntime="MyBatis3Simple">
<!-- 数据库的连接信息 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis"
userId="root"
password="123456">
</jdbcConnection>
<!-- javaBean的生成策略-->
<javaModelGenerator targetPackage="com.atguigu.mybatis.pojo" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- SQL映射文件的生成策略 -->
<sqlMapGenerator targetPackage="com.atguigu.mybatis.mapper"
targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- Mapper接口的生成策略 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.atguigu.mybatis.mapper" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- 逆向分析的表 -->
<!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
<!-- domainObjectName属性指定生成出来的实体类的类名 -->
<table tableName="t_emp" domainObjectName="Emp"/>
<table tableName="t_dept" domainObjectName="Dept"/>
</context>
</generatorConfiguration>
1.4 执行MBG插件的generate目标
如果出现报错:Exception getting JDBC Driver,可能是pom.xml中,数据库驱动配置错误
dependency中的驱动
mybatis-generator-maven-plugin插件中的驱动
两者的驱动版本应该相同
执行结果
2.QBC
2.1查询
selectByExample:按条件查询,需要传入一个example对象或者null;如果传入一个null,则表示没有条件,也就是查询所有数据
example.createCriteria().xxx:创建条件对象,通过andXXX方法为SQL添加查询添加,每个条件之间是and关系
example.or().xxx:将之前添加的条件通过or拼接其他条件
@Test public void testMBG() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
EmpExample example = new EmpExample();
//名字为张三,且年龄大于等于20
example.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);
//或者did不为空
example.or().andDidIsNotNull();
List<Emp> emps = mapper.selectByExample(example);
emps.forEach(System.out::println);
}
2.2 增改
updateByPrimaryKey:通过主键进行数据修改,如果某一个属性值为null,也会将对应的字段改为null
mapper.updateByPrimaryKey(new Emp(1,"admin",22,null,"456@qq.com",3));
updateByPrimaryKeySelective()
:通过主键进行选择性数据修改,如果某个属性值为null,则不修改这个字段
mapper.updateByPrimaryKeySelective(new Emp(2,"admin2",22,null,"456@qq.com",3));
总结:选择性修改或者查询(后缀带selective):当传入的属性条件中有null时,查询或者修改的SQL语句中不会出现该属性对应的字段,进而就不会利用该字段查询或者修改数据库表中对应字段的值了
普通修改:当传入的属性条件中有null时,SQL语句中也会出现该属性对应的字段,进而会进行该字段的查询或者修改数据库表中对应字段的值为null
3.分页插件
3.1分页插件使用步骤
3.1.1添加依赖
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
3.1.2配置分页插件
在MyBatis的核心配置文件(mybatis-config.xml)中配置插件
<plugins>
<!--设置分页插件-->
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
3.2 分页插件的使用
3.2.1 开启分页功能
在查询功能之前使用 PageHelper.startPage(int pageNum, int pageSize) 开启分页功能
pageNum:当前页的页码
pageSize:每页显示的条数
@Test
public void testPageHelper() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
//访问第一页,每页四条数据
PageHelper.startPage(1,4);
List<Emp> emps = mapper.selectByExample(null);
emps.forEach(System.out::println);
}
3.3 分页相关数据
3.3.1方法一:直接输出
@Test
public void testPageHelper() throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
//访问第一页,每页四条数据
Page<Object> page = PageHelper.startPage(1, 4);
List<Emp> emps = mapper.selectByExample(null);
//在查询到List集合后,打印分页数据
System.out.println(page);
}
分页相关数据:
Page{count=true, pageNum=1, pageSize=4, startRow=0, endRow=4, total=8, pages=2, reasonable=false, pageSizeZero=false}
[Emp{eid=1, empName=‘admin’, age=22, sex=‘男’, email=‘456@qq.com’, did=3}, Emp{eid=2, empName=‘admin2’, age=22, sex=‘男’, email=‘456@qq.com’, did=3},
Emp{eid=3, empName=‘王五’, age=12, sex=‘女’, email=‘123@qq.com’, did=3}, Emp{eid=4, empName=‘赵六’, age=32, sex=‘男’, email=‘123@qq.com’, did=1}]
3.3.2方法二 使用PageInfo
在查询获取list集合之后,使用PageInfo<T> pageInfo = new PageInfo<>(List<T> list, intnavigatePages)
获取分页相关数据
list:分页之后的数据
navigatePages:导航分页的页码数
@Test
public void testPageHelper(){
try {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
PageHelper.startPage(6,4);
List<Emp> list = mapper.selectByExample(null);
PageInfo<Emp> page = new PageInfo<>(list, 5);
System.out.println(page);
} catch (IOException e) {
e.printStackTrace();
}
}
分页相关数据:
PageInfo
{pageNum=6, pageSize=4, size=4, startRow=21, endRow=24, total=67, pages=17,
list=Page{count=true, pageNum=6, pageSize=4, startRow=20, endRow=24, total=67, pages=17, reasonable=false, pageSizeZero=false}[Emp{eid=24, empName=‘a’, age=null, sex=‘null’, email=‘null’, did=null}, Emp{eid=25, empName=‘a’, age=null, sex=‘null’, email=‘null’, did=null}, Emp{eid=26, empName=‘a’, age=null, sex=‘null’, email=‘null’, did=null}, Emp{eid=27, empName=‘a’, age=null, sex=‘null’, email=‘null’, did=null}],
prePage=5, nextPage=7, isFirstPage=false, isLastPage=false, hasPreviousPage=true, hasNextPage=true, navigatePages=5, navigateFirstPage=4, navigateLastPage=8, navigatepageNums=[4, 5, 6, 7, 8]}
其中list中的数据等同于方法一中直接输出的page数据
总结:
-
limit index,pageSize
-
index:当前页的起始索引
-
pageSize:每页显示的条数
-
pageNum:当前页的页码
index=(pageNum-1)pageSize -
使用MyBatis的分页插件实现分页功能:
-
1、需要在查询功能之前开启分页
-
PageHelper.startPage(int pageNum, int pageSize);
-
2、在查询功能之后获取分页相关信息
-
PageInfo<Emp> page = new PageInfo<>(list, 5);
-
list表示分页数据
-
5 表示当前导航分页的数量
3.3.3 常用数据:
数据 | 功能 |
---|---|
pageNum | 当前页的页码 |
pageSize | 每页显示的条数 |
size | 当前页显示的真实条数 |
total | 总记录数 |
pages | 总页数 |
prePage | 上一页的页码 |
nextPage | 下一页的页码 |
isFirstPage/isLastPage | 是否为第一页/最后一页 |
hasPreviousPage/hasNextPage | 是否存在上一页/下一页 |
navigatePages | 导航分页的页码数 |
navigatepageNums | 导航分页的页码,[1,2,3,4,5] |
3 常用注解
注解 | 功能 |
---|---|
@Param | 标识mapper接口中的方法参数,此时,会将这些参数放在map集合中 |
@MapKey注解 | 接收多个查询记录到map集合中 |
总结
对SSM整合前置知识的一个简单整合,后续会进行补充。