三层架构
MVC:web开发中,使用mvc架构模式。m:数据,V:视图,C:控制器
C控制器:接收请求,调用service对象,显示请求的处理结果,当前使用servlet作为控制器
V视图:现在使用jsp,html,css,js。显示请求处理的结果,把M中的数据显示出来
M数据:来自数据库mysql,来自文件,来自网络
mvc作用:
[1]实现解耦合。
[2]让mvc各负其职。
[3]使系统扩展更好,更容易维护。
三层架构:
1、界面层(视图层):接收用户的请求,调用service,显示请求的处理结果的。包含了jsp,html,servlet等对象。
2、业务逻辑层:处理业务逻辑,使用算法处理数据的。把数据返回给界面层。对应的是service包。
3、持久层(数据库访问层):访问数据库,或者读取文件,访问网络,获取数据。对应的包是Dao
三层架构请求处理流程
用户发起请求----->界面层------>业务层逻辑层------->持久层----->数据库(mysql)
三层架构模式和框架
每一层对应着一个框架
(1)界面层-----SpringMVC框架
(2)业务层-----Spring
(3)持久层-----MyBatis框架
框架
(1)什么是框架[framework]
框架:就是一个软件,完成了部分的功能。软件中的类和类之间的方法调用都已经规定好了
通过这些可以完成某些功能,框架看作是模板。
框架是可以升级的,改造的。框架是安全的。
框架是对某一方面有用的,不是全能的。
Mybatis框架
mybatis可以操作数据库,对数据执行增删改查,看作是高级的jdbc。解决jdbc的缺点
mybatis能做什么
[1]注册驱动
[2]创建jdbc中使用的Connection,Statement,ResultSet
[3]执行sql语句,得到ResultSet
[4]处理ResultSet,把记录集中的数据转为Java对象,同时还能把Java对象放入到List集合
[5]关闭资源
[6]实现sql语句和Java代码的解耦合
学习链接:https://mybatis.org/mybatis-3/zh/getting-started.html
下载链接:https://github.com/mybatis/mybatis-3
[1]创建student表(id,name,email,age)
[2]新建maven项目
[3]修改pom.xml
1、加入依赖Mybatis依赖,MySQL驱动,junit
2、在加入资源插件
[4]创建实体类Student。定义属性,属性名和列名保持一致
[5]创建Dao接口,定义操作数据库的方法
[6]创建xml文件(mapper文件),写sql语句
mybatis框架推荐是把sql语句和Java代码分开
mapper文件:定义和Dao接口在同一目录,一个表一个mapper文件
[7]创建mybatis的主配置文件(xml文件):有一个,放在resources文件下
1、定义创建连接实例的数据源(DataSource)对象
2、指定其他mapper文件的位置
[8]创建测试内容
使用main方法,测试mybatis访问数据库
也可以使用junit访问数据库
由mybatis框架在程序执行期间,根据自己的Dao接口,创建一个内存中的接口实现类对象
mybatis把这个技术叫做Dao技术(动态代理,Dao的动态代理)
Dao代理技术:由mybatis创建StudentDao接口的实现类Proxy(StudentDaoImpl),使用框架创建的StudentDaoImpl代替
你自己手工实现的StudentDaoImpl类的功能,不用开发人员写Dao接口的实现类。
Dao代理
mybatis提供代理:mybatis创建Dao接口的实现类对象,完成对sql语句的执行。
mabatis创建一个对象代替你的Dao实现类功能。
使用mybatis代理要求:
[1]mapper文件中的namespace一定要dao接口的全限定名称
[2]mapper文件中标签的id是dao接口方法名称
mybatis代理实现方式
使用SqlSession对象的方法getMapper(dao.class)
例如:现在有StudentDao接口
SqlSession session=MybatisUtils.getSqlSession();
StudentDao dao=session.getMapper(Student.class)
Student stu=dao.selectById(1001);
上面代码中
StudentDao dao=session.getMapper(Student.class)
等同于
StudentDao dao=new StudentDaoImpl();
理解参数
理解参数是:通过Java程序把数据传入到mapper文件中的sql的语句。
参数主要是指dao接口方法的形参
parameterType
parameterType:表示参数的类型,指定dao接口的形参数据类型。
这个属性的值可以使用Java类型的全限定名称或者mybatis定义的别名
这个形参得到数据类型是给mybatis使用,mybatis在给sql语句的参数赋值使用。
PreparedStatement.setXXX(Statement,values)
parameterType:表示参数的类型,指定dao接口的形参数据类型。
这个属性的值可以使用Java类型的全限定名称或者mybatis定义的别名
mybatis执行的sql语句: select id,name,email,age from student where id = ?
?是占位符,使用jdbc中的PreparedStatement执行的sql语句
PreparedStatement pst=con.preparedStatement(sql);
给?位置赋值pst.setInt(1,1005);
第一种用法:
Java类型的全限定类型名称 parameterType="java.lang.Integer"
第二种用法:
mabatis定义的Java类型的别名 parameterType="int"
parameterType:mybatis通过反射机制可以获取Dao接口方法参数的类型,可以不写
简单参数
Dao接口中方法的参数只有一个简单类型(Java基本类型和String),占位符#{任意字符},和方法的参数无关
Student selectByEmail(String email);
@Param:命名参数,在方法的形参前面使用的,定义参数名。这个名称可以在mapper文件中。
List selectByNameOrAge(@Param(value = "myname") String name, @Param(value = "myage") Integer age);
多个简单类型的参数
当使用了@Param命名后,例如@Param("myname")
在mapper中,使用#{命名的参数},例如#{myname}
Dao接口中多个简单类型的参数,使用位置
参数位置:dao接口中方法的形参列表,从左往右,参数位置是0,1,2,3......
语法格式:#{arg0},#{arg1},#{arg2}
Dao接口方法
List selectByPosition(String name, Integer age);
Mapper
Dao接口参数是一个Map
Dao接口方法
List selectStudentByMap(Map map);
Mapper
#和$的区别
#占位符
语法:#{字符}
mybatis处理#{}使用jdbc对象是PrepareStatement对象
mybatis创建PrepareStatement对象,执行sql语句
String sql="select * from student where name=? or age=?"
PrepareStatement pst=con.prepreStatement(sql);
pst.setString(1,"春哥");
pst.setInt(2,21);
ResultSet rs=pst.executeQuery();
#{}特点:
1、使用的PrepareStament对象,执行sql语句,效率高
2、使用的PrepareStament对象,能避免sql语句,sql语句执行更安全
3、#{}常常作为列值使用,位于等号的右侧
$占位符
语法:${字符}
mybatis执行${}占位符的sql语句
${}表示字符串连接,把sql语句的其他内容和${}内容使用 字符串 连接的方式连在一起
String sql="select * from student where id="+"10001";
mybatis创建Statement对象,执行sql语句
Statement stmt=con.con.createStatement(sql);
ResultSet rs=stmt.executeQuery();
${}的特点
1、使用Statement对象,执行sql语句,效率低
2、${}占位符的值,使用的字符串连接方式,有sql注入的风险.有代码安全的问题
3、${}数据是原样使用的,不会区分数据类型
4、${}常用作表名或者列名,在能保证数据安全的情况下使用${}
封装输出结果
resultType:执行sql得到ResultSet转换的类型,使用类型的完全限定名或别名
注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。ResultType和ResultMap,不能同时使用
mybatis:执行sql语句,得到ResultSet,转化为Java对象
resultType:在执行select时使用,作为
什么是动态sql:同一个dao的方法,根据不同的条件可以表示不同的sql语句,主要是where部分有变化
使用mybatis提供的标签,实现动态sql的能力,主要讲if,where,foreach,sql
使用动态sql的时候,dao方法的形参使用Java对象
if标签
语法:
sql代码
在mapper文件中
select * from student
sql语句
在mapper的动态sql中若出现比较符号最好将其转换为实体符号
否则XML会出现解析出错问题
< <
> >
>= >=
<= <=
where标签
使用if标签时,容易引起sql语句语法错误,使用where标签解决if产生的语法问题
使用时where,里面是一个或多个if标签,当有一个if标签判断为true,where标签
会转为WHERE关键字附加到sql语句的后面,如果if没有一个条件为true
忽略where和里面的if
语法:
sql语句1
sql语句2
where标签删除和它最近的or获取and
select * from student
or name=#{name}
or age=#{age}
mybatis-foreach循环
使用foreach可以循环数组,list集合,一般使用在in语句中
语法:
#{item的值}
标签属性:
collection:表示,循环的对象是数组,还是list集合
1、如果dao接口方法的形参是数组
collection="array"
2、如果dao接口形参是List
collection="list"
open:循环开始时的字符。sql.append("(");
close:循环结束时的字符。sql.close(")");
item:集合成员,自定义的变量。Integer item=idlist.get(i); item是集合成员
separator:集合成员之间的分隔符。sql.append(","); 集合之间的分隔符
#{item的值}:获取集合成员的值
1、foreach第一种方式,循环简单类型的list-->
dao接口:
List selectForeachOne(List IdList);
mapper:
select * from student
where id in
#{myid}
2、foreach第二种方式,循环List
dao接口:
List selectForeachOne(List IdList);
mapper:
select * from student
where id in
#{Student.id}
sql标签
sql标签标示一段sql代码,可以是表名,几个字段,where条件都可以,可以在其他地方复用sql标签的内容
使用方式:
1、在mapper文件中定义sql代码片段 部分sql语句
2、在其他的位置,使用include标签引用某个代码片段
定义代码片段
select * from student
mybatis配置文件有两大类:
1、mybatis主配置文件
提供mybatis全局设置的,包含的内容日志,数据源,mapper文件位置
2、mybatis的mapper文件
写sql语句的,一个表一个mapper文件
settings部分
settings是mybatis的全局设置,影响整个mybatis的运行,这个设置一般使用默认值就可以了
typeAliase别名
environment:环境标签,在他里面可以配置多个environment,可以表示一个数据库的连接信息
属性:
1、id自定义的环境的标识。唯一值
2、default,必须是某个environment的id属性值
transactionManager:事务管理器
属性:type表示事务管理器的类型
属性值:
1、jdbc:使用Connection对象,由mybatis自己完成事务的处理
2、MANAGED:管理,表示把事务的处理交给容器实现(由其他软件完成事务的提交,回滚)
dataSource:数据源,创建的Connection对象,连接数据库
属性:type数据源的类型
属性值:
1、POOLED,mybatis会在内存中创建PooleDatSource类,管理多个Connection连接对象使用连接池
2、UNPOOLED,不使用连接池,mybatis创建一个UnPooleDataSource这个类
每次执行sql语句先创建Connection对象再执行sql语句,最后关闭连接
3、JNDI:Java的命名和目录服务
使用数据库属性配置文件
需要把数据库的配置信息收到一个单独文件中,独立管理。这个文件扩展名properties
使用自定义的key=value的格式表示数据
使用步骤:
1、在resources目录中,创建xxx.properties
2、在文件中,使用key=value的格式定义数据
例如jdbc.url=jdbc:mysql://localhost:3306/srpingdb
3、在mybatis主配置文件,使用标签引用外部的属性配置文件
4、在使用的位置,使用${key}获取key的对应value(等号右侧的值)
mapper标签使用格式有两种常用的方式:
第一种方式,resource="mapper文件路径"
优点:文件清晰,加载文件是明确的,文件的位置比较灵活
缺点:文件比较多,代码量会比较大,管理难度大
第二种方式,使用
name:包名,mapper文件所在的包名
特点:把这个包中所有mapper文件,一次加载。
使用要求:
1、mapper文件和dao接口在同一目录
2、mapper文件和dao接口名称完全一致
4.0.0
Morries_Wu
Mybatis
1.0-SNAPSHOT
Mybatis
http://www.example.com
UTF-8
1.8
1.8
org.mybatis
mybatis
3.5.1
mysql
mysql-connector-java
5.1.9
junit
junit
4.12
test
com.github.pagehelper
pagehelper
5.1.10
src/main/java
**/*.properties
**/*.xml
false
select * from student
id,name,email
select id cid,name cname,email,age from student where id=#{stuid}
select * from student where name like #{name}
select * from student where name like "%" #{name} "%"
select * from student where id=-1
or name=#{name}
or age < #{age}
select * from student
or name=#{name}
or age=#{age}
where id in
#{myid}
select * from student
where id in
#{Student.id}
select * from student order by id
package Morries_Wu.Dao;
import Morries_Wu.Bean.Custom;
import Morries_Wu.Bean.Student;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface StudentDao02 {
Custom selectById(@Param("stuid") Integer id);
//like第一种方式
List selectLikeOne(@Param("name") String name);
//like第二种方式
List selectLikeTwo(@Param("name") String name);
//if
List selectIf(Student student);
//where
List selectWhere(Student student);
//foreach-1
List selectForeachOne(List IdList);
//foreach-2
List selectForeachTwo(List StudentList);
List selectAllStudents();
}
PageHelper做数据分页。在你的select语句后面加入分页的sql内容,如果你使用的MySQL数据库
它就是在select * from student后面加入limit语句
Mybaatis通用分页插件
https://github.com/pagehelper/Mybatis-PageHelper
使用步骤:
1、加入依赖pagehelper依赖
com.github.pagehelper
pagehelper
5.1.10
2、在mybatis主配置文件,加入(plugins)插件声明
3、在select语句之前,调用PageHelper.startPage(页码,每页大小)
PageHelper.startPage(1, 2);
List stus = dao.selectAllStudents();
select id,name,email,age from student where id = #{studentId}
select id,name,email,age from student
select id,name,email,age from student where email=#{studentEmail}
select * from student where name=#{myname} or age=#{myage}
insert into student values(#{id},#{name},#{email},#{age})
select * from student where name=#{name} or age=#{age}
select * from student where name=#{p1} or age=#{p2}
select * from student where name=#{arg0} or age=#{arg1}
select * from student where name=#{myname} or age=#{myage}
update student set name=#{name},email=#{email} where id=#{id}
select * from student where name=${myname}
select * from student order by id
select * from student order by name
select * from student order by ${colName}
select count(*) from student
select * from student where id!=#{stuid}
第一章Spring概述
什么是Spring
Spring就是一个Java框架,使用Java语言开发的,轻量级的,开源的框架。可以在JavaSE,JAVAEE项目中都可以使用
Spring核心技术:IOC,AOP
Spring又叫做:容器,spring作为容器,主要装的是Java对象,可以让spring创建Java对象,给属性赋值。
Spring作用:实现解耦合,解决Java对象之间的耦合,解决模块之间的耦合
tomcat也是容器:管理的是Servlet,listener,filter等对象。创建HelloServlet类,写web.xml
spring:创建SomeServiceImpl,写spring的配置文件
spring的地址
http://spring.io
spring优点:
spring是一个框架,是一个半成品的软件,有20个模块组成,它是一个容器管理对象
容器是装东西的,Spring容器不装文本,数字。装的是对象。Spring是存储对象的容器
1、轻量
Spring框架使用的jar都比较小,一般在1M以下或者几百KB.Spring核心功能所需的jar总共在3M左右
Spring框架运行占用的资源少,运行效率高.不依赖其他jar
2、针对接口编程,解耦合
Spring提供了IOC控制反转,由容器管理对象,对象的依赖关系。原来在程序代码中的对象创建方式,现在由容器完成,对象之间的依赖解耦合
3、AOP编程的支持
通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应对
在Spring中,开发人员可以从繁杂的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,提高开发效率和质量
4、方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,而且Spring可以降低各种框架的使用难度
Spring提供了对各种优秀框架(Struts,Hibernate、Mybatis)的支持简化框架的使用
Spring像插线板一样,其他框架是插头,可以容易的组合在一起,需要使用哪个框架,就把这个插头放入插线板,不需要可以轻易的移除
IOC:Inversion of Control控制反转,是一个理论,一个指导思想,指导开发人员如何使用对象,管理对象的。
把对象的创建,属性赋值,对象的声明周期都交给代码之外的容器管理
IOC分为控制和反转
控制:对象创建,属性赋值,对象声明周期管理
反转:把开发人员管理对象的权限转移给了代码之外的容器实现,由容器完成对象的管理
正转:开发人员在代码中,使用new构造方法创建对象
开发人员掌握了对象的创建,属性赋值,对象从开始到销毁的全部过程。开发人员有对对象全部控制
通过容器,可以使用容器中的对象(容器已经创建了对象,对象属性赋值了,对象也组装好了)
Spring就是一个容器,可以管理对象,创建对象,给属性赋值
IOC的技术实现
DI(依赖注入):Dependency Injection,缩写是DI,是IOC一种技术实现,程序只需要提供要使用的对象的名称就可以了
对象如何创建,如何从容器中查找,获取都由容器内部自己实现
依赖名词:比如说ClassA类使用了ClassB的属性或者方法,叫做ClassA依赖ClassB
Spring框架使用的DI实现IOC
通过Spring框架,只需要提供要使用的对象名词就可以了,从容器中获取名称对应的对象
Spring底层使用的反射机制,通过反射创建对象,给属性。
使用Spring:Spring作为容器管理对象,开发人员从Spring中获取要用的对象
实现步骤:
1、新建maven项目
2、加入依赖,修改pom.xml
spring-context:spring依赖
junit:单元测试
3、开发人员定义类:接口和实现类,类也可以没有接口
4、创建Spring的配置文件 作用:声明对象,把对象交给Spring创建和管理
使用标签表示对象声明,一个bean表示一个Java对象
5、使用容器中的对象
创建一个表示spring容器的对象 ApplicationContext
从容器中,根据名称获取对象,使用getBean("对象名称")
String config = "IOC/item01/Item01.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
UserService userService = (UserService) ctx.getBean("userService");
Spring的配置文件
spring标准的配置文件:
1、根标签是beans
2、beans后面的是约束文件说明
3、beans里面是bean声明
4、什么是bean:bean就是Java对象,spring容器管理的Java对象,叫做bean
Spring是什么时候创建对象?
在创建spring容器对象的时候,会读取配置文件,创建文件中声明的Java对象
优点:获取对象的速度快,因为对象已经创建好了
缺点:占用内存
spring容器创建对象,一次创建几个?
在创建容器对象时,会把配置文件中的所有对象都创建出来(spring的默认规则)
spring容器创建对象的特点:
1、容器对象ApplicationContext:接口
通过ApplicationContext对象,获取要使用的其他Java对象,执行getBean("")
2、spring默认是调用类的无参构造方法,创建对象
3、spring读取配置文件,一次创建好所有的Java对象,都放到map中
DI:给属性赋值
spring调用类的无参构造方法,创建对象.对象创建后给属性赋值.
给属性赋值
1、xml配置文件中的标签和属性
2、使用注解
DI分类:
1、set注入,设值注入
2、构造注入
基于xml的DI
在xml配置文件中使用标签和属性,完成对象创建,属性赋值。
1、set注入,也叫设值注入[和属性无关]
spring调用类中的set方法,在set方法中可以完成属性赋值,推荐使用
2、引用类型注入
构造注入
构造注入:spring调用类中的有参构造方法,在创建对象的同时,给属性赋值
引用类型的自动注入
概念:spring可以根据某些规则给引用类型完成赋值,只对引用类型有效。规则byName,byType
1、byName(按名称注入):Java 类中引用类型属性名称和spring容器中bean的id名称一样的
且数据类型也是一样的,这些bean能够赋值给引用类型
语法:
简单类型赋值
2、byType(按类型注入):Java类中引用类型的数据类型和spring容器中bean的class值是同源关系
这些bean赋值给引用类型
同源关系:
1、Java中引用类型的数据类型和bean的class值是一样的
2、Java中引用类型的数据类型和bean的class值是父子类关系的
3、Java中引用类型的数据类型和bean的class是接口和实现类关系的
注意:在xml配置文件中,符合条件的对象
只能有一个多于一个就会报错
项目中使用多个Spring配置文件
分多个配置文件的方式:
1、按功能模块分,一个模块一个配置文件
2、按类的功能分,数据库操作相关的类在一个文件,service类在一个配置文件,配置redis,事务等等的一个配置文件
spring管理多个配置文件:常用的是包含关系的配置文件,项目中有一个总的文件,里面有import标签包含其他的多个配置文件
语法:
总的文件(xml)
关键字"classpath":表示类路径,也就是类文件(class文件)所在的目录,spring到类路径中加载文件
什么时候使用classpath:在一个文件中要使用其他文件,需要使用classpath
基于注解的DI:使用spring提供的注解,完成Java对象创建,属性赋值。
注解使用的核心步驟:
1、在源代码加入注解:@Component()
2、在spring的配置文件,加入组件扫描器的标签
注意:
使用value指定对象的名称
@Component(value = "myStudent")
省略value
@Component("myStudent")
没有提供自定义对象名称,使用框架的默认对象名称:类名首字母小写
和@Component功能相同的创建对象的注解
1、@Repository:放在dao接口的实现类上面,表示创建dao对象,持久层,能访问数据库
2、@Service:放在业务层接口的实现类上面,表示创建业务层对象,业务层对象有事务的功能
3、@Controller:放在控制器类的上面,表示创建控制器对象。属于表示层对象。
控制器对象能接收请求,把请求的处理结果显示给用户
以上四个注解都能创建对象,但是@Repository,@Service,@Controller有角色说明,表示对象是分层的
对象是属于不同层的,具有额外的功能
扫描多个包的三种方式
第一种,使用多次组件扫描器
第二种,使用分隔符(;或者,),指定多个包
第三种指定父包
创建对象的注解
@Component[Bean]、@Repository[Dao层]、@Service[业务层]、@Controller[Web服务器专用]
简单类型属性赋值
@Value
引用类型赋值
@Autowired:spring提供的注解.支持byName,byType
@Autowired:默认就是byType
@Autowired @Qualifier:使用byName
@Resource:来自jdk中的注解,给引用类型赋值的,默认是byName
@Resource:先使用byName,再byType
@Resource(name="bean的名称"):只使用byName注入w
IOC总结
IOC:管理对象的,把对象放在容器中,创建,赋值,管理依赖对象
IOC:通过对象,实现解耦合,IOC解决处理业务逻辑对象之间的耦合关系,也就是service和dao之间的解耦合
spring作为容器适合管理什么对象:
1、service对象,dao对象
2、工具类对象
不适合交给spring的对象
1、实体类
2、servlet,listener,filter等web中的对象,他们是tomcat创建和管理的
package IOC.items.item02;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @Component: 表示创建对象, 对象放到容器中, 作用是
* 属性:value,表示对象名称,也就是bean的id属性值
* 位置:在类的上面,表示创建此类的对象
* @Component(value = "myStudent") 等同于
*
*
* 和@Component功能相同的创建对象的注解
* 1、@Repository:放在dao接口的实现类上面,表示创建dao对象,持久层,能访问数据库
* 2、@Service:放在业务层接口的实现类上面,表示创建业务层对象,业务层对象有事务的功能
* 3、@Controller:放在控制器类的上面,表示创建控制器对象。属于表示层对象。
* 控制器对象能接收请求,把请求的处理结果显示给用户
*
* 以上四个注解都能创建对象,但是@Repository,@Service,@Controller有角色说明,表示对象是分层的
* 对象是属于不同层的,具有额外的功能
*/
//使用value指定对象的名称
//@Component(value = "myStudent")
//省略value
@Component("myStudent")
//没有提供自定义对象名称,使用框架的默认对象名称:类名首字母小写
//@Component
public class Student {
/**
* 简单类型属性赋值:@Value
*
* @Value:简单类型属性赋值 属性:value简单类型属性值
* 位置:
* 1、在属性定义的上面,无需set方法,推荐使用
* 2、在set方法的上面
*/
//使用外部属性文件中的数据,语法${"key"}
@Value("${myname}")
private String name;
private int age;
public Student() {
System.out.println("Student无参数构造方法");
}
public void setName(String name) {
System.out.println("setName=" + name);
this.name = name;
}
@Value("${myage}")
public void setAge(int age) {
System.out.println("setAge=" + age);
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package IOC.items.item04;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("myStudent")
public class Student {
//${properties文件中的value}
@Value("${myname}")
private String name;
@Value("${myage}")
private int age;
/**
* 引用类型
*
* @Autowired: spring框架提供的, 给引用类型赋值, 使用自动注入原理。
* 支持byName,byType.默认是byType
* 位置:
* 1、在属性定义的上面,无需set方法,推荐使用
* 2、在set方法的上面
*
* byName自动注入:
* 1、@Autowired:给引用类型赋值
* 2、@Qualifer(value="bean的id") 从容器中找到指定名称对象,把对象赋值给引用类型
*/
//使用byName
@Autowired
@Qualifier(value = "mySchool")
private School school;
public Student() {
System.out.println("Student无参数构造方法");
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", school=" + school +
'}';
}
}
package IOC.items.item04;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("mySchool")
public class School {
@Value("中国云南大学")
private String name;
@Value("广东山西")
private String address;
public void setName(String name) {
this.name = name;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "School{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
}
package IOC.Item;
import IOC.items.item01.Bean.SysUser;
import IOC.items.item01.Service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test01 {
@Test
public void test01() {
String config = "IOC/item01/Item01.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
UserService userService = (UserService) ctx.getBean("userService");
SysUser user = new SysUser();
user.setName("Xixi");
user.setAge(18);
userService.addUser(user);
}
}
增加功能,导致的问题
在源代码中,业务方法中增加的功能
1、源代码可能改动的比较多
2、重复代码比较多
3、代码难以维护
AOP概念
什么是AOP [Aspect Orient Programming]:面向切面编程
Aspect:表示切面,给业务方法增加的功能,叫做切面,切面一般都是非业务功能,而且切面功能一般都是可以复用的
例如 日志功能,事务功能,权限检查,参数检查,统计信息等等
Orient:面向,对着
Programming:编程。
当目标方法需要一些功能时,可以在不修改,不能修改源代码的情况下,使用aop技术在程序执行期间,生成代理对象
通过代理执行业务方法,同时增加功能
怎么理解面向切面编程?以切面为核心设计开发你的应用
1、设计项目时,找出切面的功能
2、安排切面的执行时间,执行的位置
AOP作用
1、让切面功能复用
2、让开发人员专注业务逻辑,提高开发效率
3、实现业务的解耦和其他非业务功能解耦合
4、给存在的业务方法,增加功能,不用修改原来的代码
AOP中术语:
1、Aspect:切面,给业务方法增加的功能
2、JoinPoint:连接点,连接切面的业务方法,在这个业务方法执行时,会同时执行切面的功能
3、Pointcut:切入点,是一个或多个连接点集合。表示这些方法执行时,都能增加切面的功能
表示切面执行的位置
4、target:目标对象,给那一个对象增加切面的功能,这个对象就是目标对象
5、Adivice:通知(增强),表示切面的执行时间,在目标方法之前执行切面,还是目标方法之后执行切面
AOP中的重要三要素:Aspect,Pointcut,Adivice.
这个概念的理解是:在Adivice的时间,在Pointcut的位置,执行Aspect
AOP是一个动态的思想,在程序运行期间,创建代理(ServiceProxy),使用代理执行方法时
增加功能,这个代理对象是存在内存中的
什么时候用AOP
要给某些方法增加相同的一些功能,源代码不能改,给业务方法增加非业务功能,也可以使用AOP
AOP技术思想的实现
使用框架实现AOP,实现AOP的框架有很多,
1、Spring:Spring框架实现AOP思想中的部分功能,Spring框架实现AOP的操作比较繁杂,
2、Aspectj:独立的框架,专门是AOP
使用Aspectj框架实现AOP
通知:
Aspectj框架可以使用注解和xml配置文件两种方式实现AOP
Aspectj表示切面执行的时间,用的通知(Advice).这个通知可以使用注解表示
讲5个注解,表示切面的5个执行时间,这些注解叫做通知注解
@Before:前置通知 在目标方法之前执行的
@AfterRetunring:后置通知 在目标方法之后执行的
@Around:环绕通知
@AfterThrowing:异常通知
@After:最终通知
一个目标方法可以加多个通知
Pointcut位置
Pointcut用来表示切面执行的位置,使用Aspectj中切入点表达式
切入点表达式语法:execution(方法的定义)
使用aspectj框架的注解,实现前置通知
实现步骤:
1、新建maven项目
2、修改pom.xml加入依赖
spring-context依赖,spring-aspects依赖(能使用aspects框架的功能)
3、创建业务接口和实现类
4、创建一个叫做切面类,是一个普通类
[1]在类的上面加入@Aspect
[2]在类定义方法,方法表示切面的功能
在方法的上面加入Aspect框架中的通知注解,例如@Before(value="切入点表达式")
5、创建spring配置文件
[1]声明目标对象
[2]声明切面类对象
[3]声明自动代理生成器
6、创建测试类,测试目标方法执行时,增加切面的动能
AspectJ定义了专门的表达式用于指定切入点,表达式的原型是:
execution(public * *(..)) 指定切入点:任意公共方法
execution(* set *(..)) 指定任何一个以 "set" 开始的方法
Aspect:切面类注解
位置:放在某个类的上面
作用:表示当前类是切面类
切面类:表示包含切面功能的类
@Before:前置通知 属性:value 切入点表达式,表示切面的执行位置
在这个方式时,会同时执行切面的功能
位置:在方法的上面
特点:
[1]执行时间,在目标方法之前执行的
[2]不会影响目标方法的执行
[3]不会修改目标方法的执行结果
切面类中的通知方法,可以有参数,也可以没有
JoinPoint必须是他
JoinPoint:表示正在执行的业务方法,相当于反射中的Method
使用要求:必须是参数列表的第一个
作用:获取方法执行时的信息,例如方法名称,方法的参数集合
@Before(value = "execution(* *..SomeServiceImpl.do*(..))")
@Around环绕通知
ProceedingJoinPoint extends JoinPoint
@Around(value="切入点表达式")
使用环绕通知:就是调用切面类中的通知方法
位置:在方法的上面
返回值:Object,表示调用目标方法希望得到执行结果(不一定是目标方法自己的返回值)
参数:ProceedingJoinPoint
作用:执行目标方法的,等于Method.invoke()
虽然执行了doFirst目标方法,但是实际上只是执行了MyAspect类的myAround方法
特点:
1、在目标方法的前和后都能增强功能
2、控制目标方法是否执行
3、修改目标方法的执行结果
@AfterThrowing异常通知
语法@AfterThorwing(value="切入点表达式",throwing="自定义变量")
@After最终通知
语法@after(value="切入点表达式")
@Pointcut定义和管理切入点注解
@Pointcut(value="切入点表达式")
@Pointcut(value = "execution(* *..SomeServiceImpl.doThird(..))")
public void mypt() {
无需代码
}
package AOP.Items.item01.handle;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import java.util.Date;
/**
* Aspect:切面类注解
* 位置:放在某个类的上面
* 作用:表示当前类是切面类
* 切面类:表示包含切面功能的类
*/
@Aspect
public class MyAspect {
/**
* 定义方法,表示切面的具体功能
* 前置通知方法的定义
* [1]方法是public
* [2]方法是void
* [3]方法名臣自定义
* [4]方法可以有参数,如果有是JoinPoint也可以没有
*/
/**
* @Before:前置通知 属性:value 切入点表达式,表示切面的执行位置
* 在这个方式时,会同时执行切面的功能
* 位置:在方法的上面
* 特点:
* [1]执行时间,在目标方法之前执行的
* [2]不会影响目标方法的执行
* [3]不会修改目标方法的执行结果
*/
/*
@Before(value = "execution(public void AOP.Items.item01.sevice.serviceImpl.SomeServiceImpl.doSome(String , int ))")
public void myBefore01() {
//切面的功能代码
System.out.println("前置通知,切面功能,在目标方法之前先执行" + new Date());
}
@Before(value = "execution(void AOP.Items.item01.sevice.serviceImpl.SomeServiceImpl.doSome(String , int ))")
public void myBefore02() {
//切面的功能代码
System.out.println("前置通知,切面功能,在目标方法之前先执行" + new Date());
}
*/
/**
* 切面类中的通知方法,可以有参数,也可以没有
* JoinPoint必须是他
* JoinPoint:表示正在执行的业务方法,相当于反射中的Method
* 使用要求:必须是参数列表的第一个
* 作用:获取方法执行时的信息,例如方法名称,方法的参数集合
*/
@Before(value = "execution(* *..SomeServiceImpl.do*(..))")
public void myBefore03(JoinPoint joinPoint) {
//获取方法的定义
System.out.println("前置通知中,获取目标方法的定义:" + joinPoint.getSignature());
System.out.println("前置通知中,获取方法名称:" + joinPoint.getSignature().getName());
//获取方法执行时参数
Object[] args = joinPoint.getArgs();//数组中存放的是,方法的所有参数
for (Object arg : args) {
System.out.println("前置通知,获取方法的参数:" + arg);
}
String methodName = joinPoint.getSignature().getName();
if ("doSome".equals(methodName)) {
//切面的功能代码
System.out.println("doSome输出日志-------前置通知,切面功能,在目标方法之前先执行" + new Date());
} else if ("doOther".equals(methodName)) {
System.out.println("doOther前置通知,作为方法名称,参数的记录");
}
}
}
package AOP.Items.item02.handle;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
/**
* Aspect:切面类注解
* 位置:放在某个类的上面
* 作用:表示当前类是切面类
* 切面类:表示包含切面功能的类
*/
@Aspect
public class MyAspect {
/**
* 定义方法,表示切面的具体功能
* 后置通知方法的定义
* [1]方法是public
* [2]方法是void
* [3]方法名称自定义
* [4]方法有参数,推荐使用Object类型
*/
/**
* @AfterReturning:后置通知 属性:value切入点表达式
* returning:自定义的变量,表示目标方法的返回值的
* 自定义变量名称必须和通知方法的形参名一样
* 位置:在方法的上面
* 特点:
* [1]在目标方法之后,执行的
* [2]能获取到目标方法的执行结果
* [3]不会影响目标方法的执行
*
* 方法的参数:
* Object res:表示目标方法的返回值,使用res接收doOter的调用结果
* Object res=doOhter();
* 后置通知的执行顺序
* Object res=SomeServiceImpl.doOther(..);
* myAfterReturning(res);
*
* 思考:
* 1、doOther方法返回是String,Integer,long等基本类型
* 在后置通知中,修改返回值,是不会影响目标方法的最后调用结果
* 2、doOther返回结果是对象类型,例如Student
* 在后置通知方法中,修改这个Student对象的属性,会不会影响最后的调用结果
*/
@AfterReturning(value = "execution(* *..SomeServiceImpl.doOther(..))", returning = "res")
public void myAfterReturning(Object res) {
//修改目标方法的返回值
if (res != null) {
res="Hello AspectJ";
}
System.out.println("后置通知,在目标方法之后,执行的。能拿到执行结果" + res);
//Obeject res有什么用
/*
if ("abcd".equals(res)) {
System.out.println("根据返回值的不同,做不同的增强功能");
} else if ("add".equals(res)) {
System.out.println("doOthre做了添加数据库,我做了备份数据");
}
*/
}
}
package AOP.Items.item03.handle;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import java.util.Date;
/**
* Aspect:切面类注解
* 位置:放在某个类的上面
* 作用:表示当前类是切面类
* 切面类:表示包含切面功能的类
*/
@Aspect
public class MyAspect {
/**
* 环绕方法,定义表示切面的具体功能
* 环绕通知方法的定义
* [1]方法是public
* [2]方法是必须有返回值,推荐使用Object类型
* [3]方法名称自定义
* [4]方法必须有ProceedingJoinPoint参数.
*
* @Around:环绕通知 属性:value切入点表达式
* 位置:在方法的上面
* 返回值:Object,表示调用目标方法希望得到执行结果(不一定是目标方法自己的返回值)
* 参数:ProceedingJoinPoint
* 作用:执行目标方法的,等于Method.invoke()
*
* 虽然执行了doFirst目标方法,但是实际上只是执行了MyAspect类的myAround方法
*/
@Around(value = "execution(* *..SomeServiceImpl.doFirst(..))")
public Object myAround(ProceedingJoinPoint point) throws Throwable {
//获取方法执行时的参数值
Object[] args = point.getArgs();
String name = "";
if (args != null && args.length > 0) {
Object arg = args[0];
if (arg != null) {
name = (String) arg;
}
}
Object methodReturn = null;
System.out.println("执行了环绕通知,在目标方法之前,输出日志时间" + new Date());
//执行目标方法ProceedingJoinPoint,表示doFirst
if ("Morries".equals(name)) {
methodReturn = point.proceed();//method.invoke(),表示执行doFirst()方法本身
}
if (methodReturn != null) {
methodReturn = "环绕通知中,修改目标方法原来的执行结果";
}
System.out.println("执行了环绕通知,在目标方法之后,增加了事务提交功能");
//return "Hello Around,不是目标方法的执行结果";
return methodReturn;
}
}
package AOP.Items.item01.sevice.serviceImpl;
import AOP.Items.item01.sevice.SomeService;
public class SomeServiceImpl implements SomeService {
@Override
public void doSome(String name, int age) {
System.out.println("业务方法doSome(),创建商品的订单");
}
@Override
public void doOther() {
System.out.println("业务方法doOther()");
}
}
spring能集成很多的框架,是spring一个优势功能,通过集成功能,让开发人员使用其他框架更方便
集成使用的是spring IOC核心技术
要使用框架,例如mybatis,怎么使用mybatis
使用mybatis,需要创建mybatis框架中的某些对象,使用这些对象,就能使用mybatis提供的功能了
分析:mybatis执行sql语句,需要使用那些对象
1、需要有Dao接口的代理对象,例如StudentDao接口,需要一个它的代理对象
使用SqlSession.getMapper(StudentDao.class),得到dao代理对象
2、需要有SqlSessionFactory,创建SqlSessionFactory对象,才能使用openSession()得到SqlSession对象
3、数据源DataSource对象,使用一个更强大,功能更多的连接池对象代替mybatis自己的PooledDataSource
事务管理器
1、使用jdbc访问数据库,事务处理
public void updateAccount(){
Connection con=....
con.setAutoCommit(false);
stat.insert();
stat.update();
con.commit();
con.setAutocommit(true);
}
2、mybatis执行数据库,处理事务
public void updateAccount(){
SqlSession session=SqlSession.openSession(false);
try{
session.insert("insert into student.....");
session.update("update school.....");
session.commit();
}catch(Exception e){
session.roollback();
}
}
1、使用的mysql数据库,使用学生表student2(id int 主键列 自动增长,
name varchar(20),
age int )
2、创建maven项目
3、加入依赖
spring依赖,mybatis依赖,mysql驱动
mybatis-spring依赖(mybatis网站上提供的,用来在spring项目中,创建mybatis对象)
spring有关事务的依赖
mybatis和spring整合的时候,事务是自动提交的
4、创建实体类Student
5、创建Dao接口和mapper文件写sql语句
6、写mybatis主配置文件
7、创建service接口和他的实现类
8、创建spring的配置文件
[1]声明数据源DataSource,使用的阿里云Druid连接池
[2]声明SqlSessionFactoryBean类,在这个类内部创建的是SqlSessionFactory对象
[3]声明MapperScannerConfiguration类,在内部创建Dao代理对象
创建好的对象都放在spring容器中
[4]声明Service对象,把[3]中的dao赋值给service属性
事务定义的接口TransactionDefinition
TransactionDefinition接口,定义了三类常量,定义了有关事务控制的属性
事务的属性:
1、隔离级别
2、传播行为
3、事务的超时
给业务方法说明事务属性
隔离级别:控制事务之间影响的程度
1、DEFAULT:采用DB默认事务隔离级别,Mysql的默认为REPETABLE_READ,Oracl默认为READ_COMMITTED
2、READ_UMCOMMITTED:读未提交,未解决任何并发问题
3、READ_COMMITTED:读已提交,解决脏读,存在不可重复读与幻读
4、REPEATALE_READ:可重复读,解决脏读,不可重复读,存在幻读
5、SERIALIZABLE:串行化,不存在并发问题
超时时间
超时时间,以秒为单位,整数值,默认是-1
超时时间:表示一个业务方法最长的执行时间,没有达到时间执行完毕,spring回滚事务
传播行为
传播行为有七个
传播行为:业务方法在调用时,事务在方法之间的,传递和使用
使用传播行为,标识方法有无事务
1、PROPAGATION_REQUIRED
spring默认传播行为,方法调用的时候,如果存在事务就是使用当前的事务
如果没有事务则新建事务,方法在新事务中执行
2、PROPAGATION_REQUIRES_NEW
方法需要一个新事务,如果调用方法时,存在一个事务,则原来的事务暂停,直到新事务执行完毕
如果方法调用时,没有事务,则新建一个事务,在新事务执行代码
3、PROPAGATION_SUPPORTS
SUPPORTS:支持,方法有事务可以正常执行,没有事务也可以正常执行
Spring框架使用事务管理器对象,管理所有的事务
事务管理器接口:PlatformTransactionManager
作用:定义了事务的操作,主要是commit(),rollback()
事务管理器有很多实现类:一种数据库访问技术有一个实现类,由实现类具体完成事务的提交,回滚
意味着:jdbc或者mybatis访问数据库有自己的事务管理器实现类:DataSourceTransactionManager
hibernate框架,它的事务管理器实现类:HibernateTrasactionManager
事务使用的AOP的环绕通知
环绕通知:可以在目标方法的前和后都能增强功能,不需要修改代码
spring给业务方法执行,增加事务上的切面功能
@Around("execution(所有的业务方法)")
public Object myAround(ProceedingJoinPoint joinpoint){
try{
PlatformTransactionManager.beginTransaction(); 使用spring的事务管理器,开启事务
joinpoint.proceed(); 执行目标方法
PlatformTransactionManager.commit(); 业务方法提交事务,提交事务
}catch(Exception e){
PlatformTransactionManager.rollback(); 业务方法正常执行,回滚事务
}
}
Spring框架使用自己的注解@Transactional控制事务
@Transactional注解,使用注解的属性控制(隔离级别,传播行为,超时)
属性:
1、propagation:事务的传播行为,他使用的Propagation类的枚举值。Propagation.REQUIRED
2、Isolation:表示隔离级别,使用Isolation类的枚举型,表示隔离级别,默认solation.DEFAULT
3、readOnly:Boolean类型的值,表示数据库操作是否是只读的,默认是false
4、timeout:事务超时,默认是-1,整数值,单位秒,例如timeout=20
5、rollbackFor:表示回滚的异常类列表,他的值是一个数组,每个值是异常类型的class.
6、rollbackForClassName:表示回滚的异常类列表,他的值是异常类名称,是String类型的值
7、noRollbackFor:不需要回滚的异常类列表,是class类型的
8、noRollbackForClassName:不需要回滚的异常类列表,是String类型的值
位置:
[1]、在业务方法的上面,是在public方法的上面
[2]、在类的上面
注解的使用步骤:
1、在spring的配置文件,声明事务的内容
声明事务管理器,说明使用哪个事务管理器对象
声明使用注解管理事务,开启是注解驱动
2、在类的源代码中,加入@Transactional
事务的控制模式:
1、编程式,在代码中编程控制事务
2、声明式,不用编码
使用AspectJ框架在spring的配置文件中,声明事务控制
使用AspectJ的Aop,声明事务控制叫做声明式事务
1、pom.xml加入spring-aspects的依赖
2、在spring的配置文件声明事务的内容
[1]声明事务管理器
[2]声明业务方法需要的事务属性
[3]声明切入点表达式
package Tran_sale.Items.Item02.Service.Impl;
import Tran_sale.Items.Item02.Bean.Goods;
import Tran_sale.Items.Item02.Bean.Sale;
import Tran_sale.Items.Item02.Dao.GoodsDao;
import Tran_sale.Items.Item02.Dao.SaleDao;
import Tran_sale.Items.Item02.Service.BuyGoodsService;
import Tran_sale.Items.Item02.excetion.NotEnougthException;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
public class BuyGoodsServiceImpl implements BuyGoodsService {
private SaleDao saleDao;
private GoodsDao goodsDao;
public SaleDao getSaleDao() {
return saleDao;
}
public void setSaleDao(SaleDao saleDao) {
this.saleDao = saleDao;
}
public GoodsDao getGoodsDao() {
return goodsDao;
}
public void setGoodsDao(GoodsDao goodsDao) {
this.goodsDao = goodsDao;
}
/**
* @Transactional 放在public方法的上面, 表示方法有事务功能
* 第一种注释方式
* @Transactional(propagation = Propagation.REQUIRED,
* isolation = Isolation.DEFAULT,
* readOnly = false,timeout = 20,
* rollbackFor = {NullPointerException.class, NotEnougthException.class})
* 第二种方式
* @Transactional(propagation = Propagation.REQUIRED,
* isolation = Isolation.DEFAULT,
* readOnly = false, timeout = 20)
*
* 解释rollbackFor的使用:
* 1、框架首先检查方法抛出的异常是不是在rollbackFor的数组中,如果在一定回滚
* 2、如果方法抛出的异常不在rollbackFor数组中,框架会继续检查抛出的异常是不是RumtimeException
* 如果是runtimeException,一定回滚
*
* 例如 抛出SQLException,IOException
* rollbackFor={SQLException.class,IOException}
*/
//第三种方式:使用默认值 REQUIRED,发生运行时异常回滚
@Transactional
@Override
public void buy(Integer goodsId, Integer num) {
System.out.println("buy方法的开始");
//生成销售记录
Sale sale = new Sale();
sale.setGid(goodsId);
sale.setNum(num);
saleDao.insertSale(sale);
//查询商品
Goods goods = goodsDao.selectById(goodsId);
if (goods == null) {
throw new NullPointerException(goodsId + "商品不存在");
} else if (goods.getAmount() < num) {
throw new NotEnougthException(goodsId + "库存不足");
}
//更新库存
Goods buygoods = new Goods();
buygoods.setId(goodsId);
buygoods.setAmount(num);
goodsDao.updateGoods(buygoods);
System.out.println("buy方法的完成");
}
}
package com.Items.Item01.controller;
import com.Items.Item01.Bean.Student;
import com.google.gson.Gson;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* @Controller 创建控制器(处理器)对象
* 控制器:叫做后端控制器(back controller),自定义的类处理请求的
* 位置:在类的上面,表示创建此类的对象,对象放在springmvc的容器中
* @RequestMapping放在类的上面 属性 value:表示所有请求地址的公共前缀,相当于是模块名称
* 位置 在类的上面
*/
@Controller
//@RequestMapping("/test")
public class MyController {
//定义方法,处理请求 public void doGet(){}
/**
* springmvc框架,使用控制器类中的方法,处理请求
* 方法的特点:
* 1、方法的形参,表示请求中的参数
* 2、方法的返回值,表示本次请求的处理结果
*
* @RequestMapping:请求映射 属性:value 请求中的uri地址,唯一值,以 "/"开头
* method 请求方式,使用RequestMehtod.GET
* 是一个数组
* 位置:1、在方法的上面(必须的) 2、在类定义的上面(可选)
* 作用:把指定的请求,交给指定的方法处理,等同于url-pattern
* ModelAndView
* Model:表示数据
* View:表示视图
*/
//指定some.do使用get请求方式
@RequestMapping(value = "/some.do", method = RequestMethod.GET)
public ModelAndView doSome(HttpServletResponse response, HttpServletRequest request, HttpSession session) {//doGet()
//使用这个方法处理请求,能处理请求的方法叫做控制器方法
//调用service对象,处理请求,返回数据
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "处理了Some.do请求");
mv.addObject("fun", "处理了dosome方法");
/**
指定视图,setViewName("视图完整路径")
mv.setViewName("/WEB-INF/View/show.jsp");
mv.setViewName("/WEB-INF/View/other.jsp");
当配置了事务解析器,使用文件的名称作为视图名使用,叫做视图逻辑名称
使用了逻辑名称,框架使用配置文件视图解析器的前缀和后缀,拼接为完整的视图路径
/WEB-INF/View/+show+.jsp
*/
mv.setViewName("show");
//返回结果
return mv;
}
/**
* 当框架调用完dosome()方法之后,得到返回中ModelAndView
* 框架会在后续的处理逻辑值,处理mv对象里面的数据和视图
* 对数据执行request.setAttribute("msg", "处理了Some.do请求");把数据放入到request作用域
* 对视图执行forward转发操作,等同于request.getRequestDispatcher("/show.jsp").forward.....;
*/
//指定使用post
@RequestMapping(value = {"/other.do", "/second.do"}, method = RequestMethod.POST)
public ModelAndView doOther() {//doGet()
System.out.println("执行了MyController的doOther方法");
//使用这个方法处理请求,能处理请求的方法叫做控制器方法
//调用service对象,处理请求,返回数据
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "处理了other.do请求");
mv.addObject("fun", "处理了doOther方法");
mv.setViewName("show");
//返回结果
return mv;
}
//不指定method属性,请求方式没有限制
@RequestMapping(value = "/doFirst")
public ModelAndView doFirst() {//doGet()
System.out.println("执行了MyController的doFirst 方法");
//使用这个方法处理请求,能处理请求的方法叫做控制器方法
//调用service对象,处理请求,返回数据
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "处理了other.do请求");
mv.addObject("fun", "处理了doOther方法");
mv.setViewName("show");
//返回结果
return mv;
}
/**
* 逐个接收请求参数
* 要求:请求中的参数名和控制器方法的形参名一样,按名称对象接收请求参数
*
* 参数接收:
* 1、框架使用request对象,接收参数
* String name=request.getParameter("name");
* String age=request.getParameter("age");
*
* 2、在中央调度器的内部调用 doPropertyParam方法时,按名称对象传递参数
* doPropertyParam(name,Intger.valuof(age))
* 400:http status,表示客户端异常,主要是发生在用户提交参数过程中
*/
@RequestMapping(value = "/receive-property.do")
public ModelAndView doPropertyParam(String name, int age) {
System.out.println("执行了MyController的doPropertyParam方法name:" + name + "age:" + age);
ModelAndView mv = new ModelAndView();
//添加数据
mv.addObject("myname", name);
mv.addObject("myage", age);
mv.setViewName("show");
//返回结果
return mv;
}
/**
* 逐个接收请求参数:请求中参数名和形参名不一样
*
* @RequestParam:解决名称不一样的问题 属性:value 请求中的参数名
* required:boolean类型,默认是一个
* true:请求中必须有此参数,没有报错
* faslse:请求中可以没有此参数
* 位置:在形参定义的前面
*/
@RequestMapping(value = "/receive-param.do")
public ModelAndView doReceiveParam(@RequestParam(value = "rname", required = false) String name,
@RequestParam(value = "rage", required = false) int age) {
System.out.println("执行了MyController的doReceiveParam方法name:" + name + "age:" + age);
ModelAndView mv = new ModelAndView();
//添加数据
mv.addObject("myname", name);
mv.addObject("myage", age);
mv.setViewName("show");
//返回结果
return mv;
}
/**
* 使用对象接收请求中的参数
* 要求:参数名和Java对象属性名一样
* Java类需要有一个无参构造方法,属性有set方法
*
* 框架的处理:
* 1、调用Student的无参构造方法,创造对象
* 2、调用对象set方法,同名的参数,调用对应的set方法
* 参数是name,调用setName(参数值)
*/
@RequestMapping("/receive-object.do")
public ModelAndView doReceiveObject(Student student) {
System.out.println("MyController的方法doReceiveObject:" + student);
ModelAndView mv = new ModelAndView();
mv.addObject("myname", student.getName());
mv.addObject("myage", student.getAge());
mv.setViewName("show");
return mv;
}
/**
* 控制器方法返回String,表示逻辑名称,需要项目中配置视图解析器
*/
@RequestMapping(value = "/return-String-view01.do")
public String doReturnStringView01(HttpServletRequest request, String name, Integer age) {
System.out.println("MyController的方法doReturnStringView:" + name + age);
//返回结果,forward,转发到show.jsp
request.setAttribute("myname", name);
request.setAttribute("myage", age);
return "show";
}
/**
* 控制器方法返回String,表示完整视图路径,项目中不能配置视图解析器
*/
@RequestMapping(value = "/return-String-view02.do")
public String doReturnStringView02(HttpServletRequest request, String name, Integer age) {
System.out.println("MyController的方法doReturnStringView:" + name + age);
request.setAttribute("myname", name);
request.setAttribute("myage", age);
//返回结果,forward,转发到show.jsp
return "/WEB-INF/View/show.jsp";
}
/**
* 控制器方法是返回是void,响应Ajax请求,使用httpServletRequest输出数据
*/
@RequestMapping(value = "/return-void-ajax.do")
public void returnvoidAjax(HttpServletResponse response, String name, Integer age) throws IOException {
System.out.println("MyController的方法doReturnStringView:" + name + age);
//调用service得到结果对象
Student stu = new Student();
stu.setName(name + "同学");
stu.setAge(age);
//把对象转为json
Gson gson = new Gson();
String json = gson.toJson(stu);
System.out.println("服务器端对象转化为json" + json);
//输出json,响应Ajax
response.getWriter().write(json);
/**
*把对象转为json
* ObjectMapper om=new ObjectMapper();
* String json=om.writeValueAsString(stu);
* System.out.println("服务器端对象转为的json"+json);
* 输出json,响应AJAX
* response.setContentType("application/json;charset=utf-8");
* PrintWriter pw=response.getWriter();
* pw.println(json);
* pw.flush();
* pw.close();
*
*/
}
/**
* 控制器方法返回Student--json
* application/json;charset-utf-8
*
* 框架处理模式:
* 1、框架根据控制器方法的返回值类型,找到HttpMessageConverter接口的实现类
* 最后找到的是MappingJackson2HttpMessageConverter
*
* 2、使用实现类MappingJackson2HttpMessageConverter执行它的write()方法
* 把Student对象转为了json格式的数据
* 3、框架使用@ResponseBody注解,把2中的json输出给浏览器
* 设置的Content-type:application/json;charset-utf-8
*/
@RequestMapping("/doStudentJson.do")
@ResponseBody
public Student doAjaxJson(String name, Integer age) {
System.out.println("控制器方法返回自定义对象Student,转为json" + name + age);
Student stu = new Student();
stu.setName("同学" + name);
stu.setAge(age);
return stu;
}
/**
* 控制器方法返回是List--json array
* 框架的处理模式:
* 1、框架根据控制器方法的返回值类型,找到HttpMessageConverter接口的实现类
* 最后找到的是MappingJackson2HttpMessageConverter
* 2、使用实现类MappingJackson2HttpMessageConverter执行他的write()方法,把student对象转为json格式的数据
* 3、框架使用@ResponseBody注解,把2中的json输出给浏览器
*/
@RequestMapping("/doListJsonArray.do")
@ResponseBody
public List doAjaxJsonArray(String name, Integer age) {
System.out.println("控制器方法返回List,转为JsonArray" + name + age);
Student stu01 = new Student();
stu01.setName("张三同学");
stu01.setAge(20);
Student stu02 = new Student();
stu02.setName("李四同学");
stu02.setAge(26);
List stulist = new ArrayList<>();
stulist.add(stu01);
stulist.add(stu02);
return stulist;
}
/**
* 控制器方法返回String--数据
*区分返回值String是数据还是视图
*1、方法上面有@ReponseBody注解就是数据
*2、方法上面没有@ResponseBody注解就是视图
*
* Content-Type:text/plain;charset=ISO-8859-1
*解决中文,需要使用@RequestMapping的produce属性
* produce属性:指定content-Type的值
*
* 框架处理String返回值
* 1、框架使用的StringHttpMessageConverter
* 2、
*
*/
@RequestMapping(value = "/doStringData.do",produces = "text/plain;charset=UTF-8")
@ResponseBody
public String doStringData(String name,Integer age){
System.out.println("控制器方法返回String,是数据");
return"Hello SpringMVC注解式开发";
}
}
package com.Items.item04.Handle;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Date;
/**
* 拦截器
*/
public class MyInterceptor implements HandlerInterceptor {
/**
* preHandle:预先处理请求的方法[总开关]
* 参数:Object handler:被拦截的控制器对象,(MyController)
* 返回值:boolean
* true:请求是正确的,可以被Controller处理的
* MyInterceptor拦截器的preHandle
* 执行了MyController的doSome方法
* MyInterceptor拦截器的postHandle
* MyInterceptor拦截器的afterCompletion
*
* false:请求不能被处理,控制器方法不会执行,请求到此截止
* MyInterceptor拦截器的preHandle
*
* 特点:
* 1、预处理方法它的执行时间:在控制器方法之前先执行的
* 2、可以对请求做处理,可以做登录的检查,权限的判断,统计数据等等
* 3、决定请求是否执行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor拦截器的preHandle");
//提示
//request.getRequestDispatcher("/tips.jsp").forward(request, response);
return true;
}
/**
* postHandle:后处理方法
* 参数:
* Object handler:被拦截的控制器对象(MyController)
* ModelAndView mv:控制器方法的返回值(请求的执行结果)
* 特点:
* 1、在控制器方法之后执行的
* 2、能获取到控制器方法的执行结果,可以修改原来的结果
* 可以修改数据,也可以修改视图
* 3、可以看作对请求的二次处理
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor拦截器的postHandle");
if (modelAndView != null) {
//修改数据
modelAndView.addObject("mydate", new Date());
//修改视图
modelAndView.setViewName("other");
}
}
/**
* afterCompletion:最后执行的方法
* 参数:
* Object handler:被拦截的控制器对象(MyController)
* Exception ex:异常对象
* 特点:
* 1、在请求处理完成后执行的,请求处理完成的标志是视图处理完成,对视图执行forward操作后
* 2、可以做程序最后要做的工作,释放内存, 清理临时变量
* 3、方法的执行条件
* [1]当前的拦截器它的preHanlder()方法必须执行
* [2]preHandler()必须返回true
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor拦截器的afterCompletion");
//获取数据
HttpSession session = request.getSession();
Object attr = session.getAttribute("attr");
System.out.println("attr" + attr);
//删除数据
session.removeAttribute("attr");
//确定数据是否删除
attr = session.getAttribute("attr");
System.out.println("删除后,再次检查数据" + attr);
}
}
<%--
Created by IntelliJ IDEA.
User: Morries
Date: 2021/11/1
Time: 18:29
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
发起一个some.do的GET请求
发起了Student/add.do的请求
发起一个some.do的GET请求
逐个接收请求
逐个接收请求:请求中参数名和形参名不一样
对象接收参数:请求中参数名和对象属性名一样
控制器方法返回String,逻辑名称
控制器方法返回String,完整视图路径
发起forward.do
重定向Redirect
<%--
Created by IntelliJ IDEA.
User: Morries
Date: 2021/11/1
Time: 17:58
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
/WEB-INF/View/show.jsp,显示request作用域中的数据
msg数据:${msg}
msg数据:${fun}
myname数据:${myname}
myage数据:${myage}
attr数据:${attr}
contextConfigLocation
classpath:conf/applicationContext.xml
org.springframework.web.context.ContextLoaderListener
myssm
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:conf/dispatcherServlet.xml
1
myssm
*.do
characterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceRequestEncoding
true
forceResponseEncoding
true
characterEncodingFilter
/*
package Items.item01.Bean;
public class Student {
private Integer id;
private String name;
private Integer age;
public Student() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
package Items.item01.controller;
import Items.item01.Bean.Student;
import Items.item01.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
@Controller
@RequestMapping("/student")
public class StudentController {
/**
* 声明引用类型,调用引用类型的业务方法
* 引用类型自动注入@Autowired,@Resource
* 添加学生
*/
@Autowired
private StudentService service;
@RequestMapping("/addStudent.do")
public ModelAndView addStudent(Student student) {
ModelAndView mv = new ModelAndView();
//调用service,处理业务逻辑,把处理结果返回给用户
int rows = service.addStudent(student);
String msg = "注册失败!";
if (rows > 0) {
//注册成功,给用户成功的数据和视图
msg = "注册成功";
}
mv.addObject("msg", student.getName() + "," + msg);
mv.setViewName("result");
return mv;
}
@RequestMapping("/queryStudent.do")
@ResponseBody
public List queryStudents() {
List stulist = service.queryStudents();
return stulist;
}
}
package Items.item01.service;
import Items.item01.Bean.Student;
import Items.item01.dao.StudentDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
*
*
* @Service
*/
@Service
public class StudentServiceImpl implements StudentService {
/**
* dao是引用类型,StudentDao类型的对象是在Spring的配置文件中创建的对象
* 引用类型自动注入@Autowired,@Resource
*/
@Autowired
private StudentDao dao;
@Override
public int addStudent(Student student) {
int rows = dao.insertStudent(student);
return rows;
}
@Override
public List queryStudents() {
List stulist = dao.selectStudent();
return stulist;
}
}
select * from student2 order by id desc
insert into student2(name,age) values(#{name},#{age})
<%--
Created by IntelliJ IDEA.
User: Morries
Date: 2021/12/18
Time: 11:09
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
SSM
<%--
Created by IntelliJ IDEA.
User: Morries
Date: 2021/12/18
Time: 11:17
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String basePath=request.getScheme()+"://"+
request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/";
%>
浏览学生
浏览学生
<%--代表表头的意思thread--%>
id
姓名
年龄
<%--
Created by IntelliJ IDEA.
User: Morries
Date: 2021/12/18
Time: 11:06
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%String basePath=request.getScheme()+"://"+
request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/";
%>
添加
注册学生