文章目录
Spring
spring优势及开发步骤
spring 的优势
- 方便解耦,简化开发
通过Spring提供的IoC容器,可以将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的过度耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。- AOP编程的支持
通过Spring的AOP功能,方便进行面向切面编程,许多不容易用传统OOP实现的功能可以通过AOP轻松实现。- 声明式事务的支持
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务管理,提高开发效率和质量。- 方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情。- 方便集成各种优秀的框架
Spring对各种优秀框架(Struts、Hibernate、Hessian、Quartz等)的支持。- 降低JavaEE API的使用难度
Spring对Java EE API(如JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些API的使用难度大为降低。
Spring程序开发步骤
- 导入Spring开发的基本包坐标
- 编写Dao接口和实现类
- 创建Spring核心配置文件
- 在Spring配置文件中配置UserDao的实现
- 使用Spring的API获得bean对象,找容器去要对象(解耦)
Spring 配置文件
- Bean标签基本配置
Bean标签基本配置
用于配置对象交由Spring来创建
默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功基本属性:
id:Bean实例在Spring容器中的唯一标识
class:Bean的全限定名称
- Bean标签范围配置
scope:指对象的作用范围,取值如下:
取值范围 | 说明 |
---|---|
singleton | 默认值,单例的(容器中是单一对象) |
prototype | 多例的(容器中是多个对象) |
request | WEB项目中,Spring创建一个Bean的对象,将对象存入到request域中 |
session | WEB项目中,Spring创建一个Bean对象,将对象存入到session域中 |
global session | WEB项目中,应用在Portlet环境中,如果没有Portlet环境那么globalSession相当于session |
1)当scope的取值为singleton时
- Bean的实例化个数:1个
Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例
对象销毁:当应用卸载,销毁容器时,对象就被销毁了2)当scope的取值为prototype时
- Bean的实例化个数:多个
- Bean的实例化时机:当调用getBean()方法时实例化Bean
-1. 对象创建:当使用对象时,创建新的对象实例
-2. 对象运行:只要对象在使用中,就一直活着
-3. 对象销毁:当对象长时间不用时,被Java的垃圾回收器回收了
- Bean生命周期配置
- init-method:指定类中的初始化方法名称
- destory-method:指定类中销毁方法名称
- Bean实例化三种方式
- 无参构造方法实例化(重点)
- 工厂静态方法实例化
- 工厂实例方法实例化
- Bean的依赖注入分析
目前UserService实例和UserDao实例都存在于Spring容器中,当前的做法是在容器外部获得UserService实例和UserDao实例,然后在程序中进行结合。
UserService实例:
getBean(name:"userService")
获得UserService实例,发现UserService实例内部需要UserDao实例的save()方法,所以在UserService内部获得UserDao实例
getBean(name:"userDao")
相当于是在Spring容器外将Dao组装到Service内部完成的操作
- 因为UserService和UserDao都在Spring容器中,而最终程序直接使用的是UserService,所以可以在Spring容器中,将UserDao设置到UserService内部。
getBean(name:“userService”)
获得UserService实例,内部已经存在UserDao实例了,直接调用UserDao的save()方法即可- 如何将UserDao设置到UserService内部?
- Bean的依赖注入概念
依赖注入(Dependency Injection):它是Spring框架核心IOC的具体实现
- 在编写程序时,通过控制反转,把对象的创建交给了Spring,但是代码中不可能出现没有依赖的情况。IOC解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。
- 那这种业务层和持久层的依赖关系,在使用Spring之后,就让Spring来维护了。简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。
Bean的依赖注入方式
- 怎么将UserDao注入到UserService内部呢?
- 构造方法
- set方法
1)set方法注入
- P命名空间注入本质也是set方法注入,但比起上述的set方法注入更加方便,主要体现在配置文件中,如下:
首先,需要引入P命名空间:
xmlns:p="http://www/springframework.org/schema/p"
其次,需要修改注入方式2)构造方法
- Bean的依赖注入的数据类型
上面的操作,都是注入的引用Bean,除了对象的引用可以注入,普通数据类型,集合等都可以在容器中进行注入。
注入数据的三种数据类型:
- 普通数据类型
- 引用数据类型
- 集合数据类型
- 引入其他配置文件(分模块开发)
实际开发中,Spring的配置内容非常多,这就导致Spring配置很繁杂且体积很大,所以,可以将部分配置拆解到其他配置文件中,而在Spring主配置文件通过import标签进行加载。
< import resource="applicationContext-xx.xml"/>
- 知识要点
Spring的重点配置
<bean>标签
id属性:在容器中Bean实例的唯一标识,不允许重复
class属性:要实例化的Bean的全限定名
scope属性:Bean的作用范围,常用是Singleton(默认)和prototype
<property>标签:属性注入
name属性:属性名称
value属性:注入的普通属性值
ref属性:注入的对象引用值
<list>标签
<map>标签
<properties>标签
<constructor-arg>标签
<import>标签:导入其他的Spring的分文件
Spring相关的API
- ApplicationContext的继承体系
applicationContext:接口类型,代表应用上下文,可以通过其实例获得Spring容器中的Bean对象。
- ApplicationContext的实现类
- ClassPathXmlApplicationContext
它是从类的根路径下加载配置文件 推荐使用这种- FileSystemXmlApplicationContext
它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任何位置- AnnotationConfigApplicationContext
当使用注解配置容器对象时,需要使用此类来创建spring容器。它用来读取注解。
- getBean()方法使用
其中,当参数的数据类型是字符串时,表示根据Bean的id从容器中获得Bean实例,返回是Object,需要强转。当参数的数据类型是Class类型时,表示根据类型从容器中匹配Bean实例,当容器中相同类型的Bean有多个时,则此方法会报错。
- 知识要点
- Spring的重点API
ApplicationContext app = new ClasspathXmlApplicationContext("xml文件")
app.getBean("id")
app.getBean(Class)
Spring配置数据源
数据源(连接池)
作用
- 数据源(连接池)是提高程序性能出现的
- 事先实例化数据源,初始化部分连接资源
- 使用连接资源时从数据源中获取
- 使用完毕后将连接资源归还给数据源
常见的数据源(连接池):DBCP、C3P0、BoneCP、Druid等
开发步骤
- 导入数据源的坐标和数据库驱动坐标
- 创建数据源对象
- 设置数据源的基本连接数据
- 关闭数据源
手动创建
public class DataSourceTest {
@Test
//测试手动创建c3p0数据源(加载properties配置文件)
public void test3() throws Exception {
//读取配置文件
ResourceBundle rb = ResourceBundle.getBundle("jdbc");
String driver = rb.getString("jdbc.driver");
String url = rb.getString("jdbc.url");
String username = rb.getString("jdbc.username");
String password = rb.getString("jdbc.password");
//创建数据源对象,设置连接参数
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
@Test
//测试手动创建c3p0数据源
public void test1() throws Exception {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUser("root");
dataSource.setPassword("root");
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
}
Spring容器创建dataSource对象
1.4 抽取jdbc配置文件
applicationContext.xml加载jdbc.properties配置文件获得连接信息
首先,需要引入context命名空间和约束路径
- 命名空间:
- 约束路径:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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/beans/spring-context.xsd">
<!--加载外部的properties文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
</beans>
Spring注解开发
2.1 Spring原始注解
Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率。
Spring原始直接主要是替代<Bean>
的配置
注解 | 说明 |
---|---|
@component | 使用在类上用于实例化Bean |
@Controller | 使用在Web层类上用于实例化Bean |
@Service | 使用在service层类上用于实例化Bean |
@Repository | 使用在dao层类上用于实例化Bean |
@Autowired | 使用在字段上用于根据类型依赖注入 |
@Qualifier | 结合@Autowired一起使用用于根据名称进行依赖注入 |
@Resource | 相当于@Autowired+@Qualifier,按照名称进行注入 |
@Value | 注入普通属性 |
@Scope | 标注Bean的作用范围 |
@PostConstruct | 使用在方法上标注该方法是Bean的初始化方法 |
@PreDestroy | 使用在方法上标注该方法是Bean的销毁方法 |
//<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
@Component("userService")
public class UserServiceImpl implements UserService {
//<property name="userDao" ref="userDao"></property>
@Autowired
@Qualifier("userDao")
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
userDao.save();
}
}
注意:
使用注解进行开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean需要进行扫描以便识别使用注解配置的类、字段和方法
<!-- 配置组件扫描 -->
<context:component-scan base-package="com.itheima"/>
2.2 Spring新注解
使用上面的注解还不能全部替代xml配置文件,还需要使用注解替代的配置如下:
- 非自定义的Bean的配置:
<bean>
- 加载properties文件的配置:
<context:property-placeholder>
- 组件扫描的配置:
<context:componenr-scan>
- 引入其他文件:
<import>
注解 | 说明 |
---|---|
@Configuration | 用于指定当前类是一个Spring配置类,当创建容器时会从该类上加载注解 |
@ComponentScan | 用于指定Spring在初始化容器时要扫描的包。作用和在Spring的xml配置文件中的<context:component-scan base-package=“com.itheima”/>一样 |
@Bean | 使用在方法上,标注将该方法的返回值存储到Spring容器中 |
@PropertySource | 用于加载.properties文件中的配置 |
@Import | 用于导入其他配置类 |
Spring集成Junit
3.1 原始Junit测试Spring的问题
- 在测试类中,每个测试方法都有以下两行代码
这两行代码的作用是获取容器,如果不写的话,直接回提示空指针异常,所以又不能轻易删掉
ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfiguration.class)
UserService userService = app.getBean(UserService.class);
3.2 上述问题解决思路
- 让SpringJunit负责创建Spring容器,但是需要将配置文件的名称告诉它
- 将需要进行测试Bean直接在测试类中进行注入
3.3 Spring集成Junit步骤
① 导入Spring集成Junit的坐标
② 使用@Runwith注解替换原来的运行期
③ 使用@ContextConfiguration指定配置文件或配置类
④ 使用@Autowired注入需要测试的对象
⑤ 创建测试方法进行测试
Spring与Web环境集成
- ApplicationContext应用上下文获取方式
应用上下文对象是通过
new ClassPathXmlApplicationContext(spring配置文件)
方式获取的,但是每次从容器中获得Bean时都要编写,这样的弊端是配置文件加载多次,应用上下文对象创建多次。
在Web项目中,可以使用
ServletContextListener
监听Web应用的启动,我们可以在Web应用启动时,就加载Spring配置文件,创建应用上下文对象ApplicationContext
,在将其存储到最大的域servletContext
域中,这样就可以在任意位置从域中获得应用上下文ApplicationContext对象了。
- Spring提供获取应用上下文的工具
上面的分析不用手动实现,Spring提供了一个监听器
ContextLoaderListener
就是对上述功能的封装,该监听器内部加载Spring配置文件,创建应用上下文对象,并存储到ServletContext
域中,提供了一个客户端工具WebApplicationContextUtils
供使用者获得应用上下文对象。
所以我们需要做的只有两件事:
- 在
web.xml
中配置ContextLoaderListener
监听器(导入spring-web坐标)- 使用
WebApplicationContextUtils
获得应用上下文对象ApplicationContext
SpringMVC
SpringMVC简介
需求:客户端发起请求,服务端接收请求,执行逻辑并进行视图跳转
开发步骤:
- 导入SpringMVC相关坐标
- 配置SpringMVC核心控制器DispathcerServlet
- 创建Controller类和视图页面
- 使用注解配置Controller类中业务员方法的映射地址
- 配置SpringMVC核心文件spring-mvc.xml
- 客户端发起请求测试
SpringMVC的组件解析
SpringMVC的相关组件
- 前端控制器:DispatcherServlet
- 处理器映射器:HandlerMapping
- 处理器适配器:HandlerAdapter
- 处理器:Handler
- 视图解析器: View Resolver
- 视图: View
SpringMVC的执行流程
- 用户发送请求至前端控制器
DispatcherServlet
DispatcherServlet
收到请求调用HandlerMapping
处理器映射器- 处理器映射器找到具体的处理器(可以根据xml配置,注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给
DispatcherServlet
DispatcherServlet
调用HandlerAdapter
处理器适配器。HandlerAdapter
经过适配器调用具体的处理器(Controller
,也叫后端控制器)Controller
执行完成后返回ModelAndView
HandlerAdapter
将controller
执行结果ModerlAndView
返回给DispatcherServlet
DispatcherServlet
将ModelAndView传给ViewReslover
视图解析器。ViewReslover
解析后返回具体View
DispatcherServlet
根据View
进行渲染视图(即将模型数据填充至视图中)。DispatcherServlet
响应用户。
SpingMVC注解解析
SpringMVC的注解和配置
- 请求映射注解:@RequestMapping
- 视图解析器配置:
REDIRECT_URL_PREFIX=“redirect:” --重定向前缀
FORWARD_URL_PREFIX=“forward” – 转发前缀(默认值)
prefix=" " --视图名称前缀
suffix=" " --视图名称后缀
@RequestMapping
- 作用:用于建立请求URL和处理请求方法之间的对应关系
- 位置:类上,请求URL的第一级访问目录。此处不写的话,就相当于应用的根目录。方法上,请求URL的第二级访问目录,与类上的使用@ReqquestMapping标注的一级目录一起组成访问虚拟路径。
- 属性:value:用于指定请求的URL。它和path属性的作用是一样的。
method:用于指定请求的方式。
params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的key和value必须和配置的一模一样。
例如:params={“accountName”},表示请求参数必须有accountName
params={“money!100”},表示请求参数中money不能是100
组件扫描
- SpringMVC基于Spring容器,所以在进行SpringMVC操作时,需要将Controller存储到Spring容器中,如果使用@Controller注解标注的话,就需要使用
<context:component-scan base-package="com.itheima.controller"/>
进行组件扫描
SpringMVC的XML配置解析
视图解析器
- SpringMVC有默认组件配置,默认组件都是DispatcherServlet.properties配置文件中配置的,该配置文件地址org/springframework/web/servlet/DispatcherServlet.properties,该文件中配置了默认的视图解析器,如下:
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- 翻看该解析器源码,可以看到该解析器的默认设置,如下:
REDIRECT_URL_PREFIX=“redirect:” --重定向前缀
FORWARD_URL_PREFIX=“forward” – 转发前缀(默认值)
prefix=" " --视图名称前缀
suffix=" " --视图名称后缀
SpringMVC的数据响应
SpringMVC的数据响应方式
- 页面跳转
- 直接返回字符串
此种方法会将返回的字符串与视图解析器的前后缀拼接后跳转。- 通过ModelAndView对象返回。
Model:模型 作用封装数据
View:视图 作用展示数据
- 回写数据
- 直接返回字符串
- 返回对象或集合
回写数据——直接返回字符串
- Web基础阶段,客户端访问服务器端,如果想直接回写字符串作为响应体返回的话,只需要使用
response.getWriter().print("hello world")
即可,那么在Controller中想直接回写字符串该怎样呢?- ① 通过SpringMVC框架注入的response对象,使用
response.getWriter().print("hello world")
回写数据,此时不需要视图跳转,业务方法返回值为void- ② 将需要回写的字符串直接返回,但此时需要通过
@ResponseBody
注解告知SpringMVC框架,方法返回的字符串不是跳转是直接在http响应体中返回。
//①
@RequestMapping("/quick4")
public void quickMethod4(HttpServletResponse response) throws IOException{
response.getWriter().print("hello world");
}
//②
@RequestMapping("/quick5")
@ResponseBody //告知SpringMVC框架,该方法不进行视图跳转,直接进行数据响应
public void save7() throws IOException{
return "hello world";
}
回写数据——返回对象或集合
- 通过SpringMVC帮助我们对对象或集合进行json字符串的转换并回写,为处理器适配器配置消息转换参数,指定使用jackson进行对象或集合的转换,因此需要在spring-mvc.xml中进行如下配置:
<!-- 配置处理器映射器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></bean>
</list>
</property>
</bean>
在方法上添加
@ResponseBody
就可以返回json格式的字符串,但是这样配置比较麻烦,配置的代码比较多,因此,我们可以使用mvc的注解驱动代替上述配置。
<!--mvc的注解驱动-->
<mvc:annotation-driven/>
- 在SpringMVC的各个组件中,处理器映射器、处理器适配器、视图解析器称为SpringMVC的三大组件。使用mvc:annotation-driven自动加载
RequestMappingHandlerMapping
(处理映射器)和RequestMappingHandlerAdapter
(处理适配器),可用在Spring-xml.xml配置文件中使用<mvc.annotation-driven>
替代注解处理器和适配器的配置。同时使用mvc:annotation-driven默认底层就会集成jackson进行对象或集合的json格式字符串的转换。
SpringMVC获得请求数据
客户端请求参数的格式是:
name=value&name=value...
服务器端要获得请求的参数,有时还需要进行数据的封装,SpringMVC可以接收如下类型的参数:
- 基本类型参数
- POJO类型参数
- 数组类型参数
- 集合类型参数
获得基本类型参数
- Controller中的业务方法的参数名称要与请求参数的name一致,参数值会自动映射匹配。
获得POJO类型参数
- Controller中的业务方法的POJO参数的属性名与请求参数的name一致,参数值会自动映射匹配。
@RequestMapping(value="/quick10")
@ResponseBody
//期望将SpringMVC自动将User转换成Json格式的字符串
public void save10(User user) throws IOException{
System.out.println(user);
}
获得数组类型参数
- Controller中的业务方法数组名称与请求参数的name一致,参数值就会自动映射匹配。
http://localhost:8080/itheima_springmvc/quick?strs=111&strs=222&strs=333
@RequestMapping("/quick")
@ResponseBody
public void quickMethod(String[] strs) throws IOException{
System.out.println(Arrays.asList(strs));
}
获得集合类型参数
- 获得集合参数时,要将集合参数包装到一个POJO中才可以。
- 当使用ajax提交时,可以指定
contextType
为json形式,那么在方法参数位置使用@RequestBody
可以直接接受集合数据而无需使用POJO进行包装。
请求数据乱码问题
- 当post请求时,数据会出现乱码,我们可以设置一个过滤器来进行编码的过滤
<!-- 配置全局过滤的filter-->
<filter>
<filter-name>CharaterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharaterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
参数绑定注解@requestParam
- 当请求的参数名称与Controller的业务方法参数名称不一致时,就需要通过@RequestParam注解显示的绑定
注解@RequestParam参数:
- value:与请求参数名称
- required:此在指定的请求参数是否必须包括,默认是true,提交时如果没有此参数则报错
- defaultValue:当没有指定请求参数时,则使用指定的默认值赋值
获得Restful风格的参数
- Restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服务器交互类的软件,基于这个风格设计的软件可以更加简洁,更有层次,更易于实现缓存机制等。
Restful风格的请求是使用“url+请求方式”表示一次请求目的的,HTTP协议里面四个操作方式的动词如下:
- GET:用于获取资源
- POST:用于新建资源
- PUT:用于更新资源
- DELETE:用于删除资源
上述url地址/user/1中的1就是要获得的请求参数,在SpringMVC中可以使用占位符进行参数绑定,地址/user/1可以写成/user/(id),占位符(id)对应的就是1的值。在业务方法中我们可以使用@PathVariable注解进行占位符的匹配获取工作。
自定义类型转换器
- SpringMVC默认已经提供了一些常用的类型转换器,例如客户端提交的字符串转换成int型进行参数设置。
- 但是不是所有的数据类型都提供了转换器,没有提供的就需要自定义转换器,例如:日期类型的数据就需要自定义转换器。
- 自定义类型转换器的开发步骤:
①定义转换器类实现Converter接口
②在配置文件中声明转换器
③在<annotation-driven>
中引用转换器
获得Servlet相关API
SpringMVC支持使用原始ServletAPI对象作为控制器方法的参数进行注入,常用的对象如下:
- HttpServletRequest
- HttpServletResponse
- HttpSession
获得请求头
- @RequestHeader
使用@RequestHeader可以获得请求头信息,相当于web阶段学习的request.getHeader(name)
@RequestHeader注解的属性如下:
- value:请求头的名称
- required:是否必须携带此请求头
- @CooikeValue
使用@CookieValue可以获得指定Cooike的值
@CooikeValue注解的属性如下:
- value:指定cookie的名称
- required:是否必须携带此cookie
文件上传
- 文件上传客户端三要素
- 表单项 type=“file”
- 表单的提交方式是 post
- 表单的enctype属性是多部分表单形式,及enctype=“multipart/form-data”
- 文件上传原理:
- 当form表单修改为多部分表单时,request.getParameter()将失效
- enctype="application/x-www-form-urlencoded"时,form表单的正文内容格式是:
key=value&key=value&key=value
- 当form表单的enctype取值为Multipart/form-data时,请求正文内容就变成多部分形式:
单文件上传
- 导入fileupload和io坐标
- 配置文件上传解析器
- 编写文件上传代码
JdbcTemplate
- 它是spring框架中提供的一个对象,是对原始繁琐的Jdbc API对象的简单封装。spring框架为我们提供了很多的操作模板类。例如:操作关系型数据的JdbcTemplate和HibernateTemplate,操作nosql数据库的RedisTemplate,操作消息队列的JmsTemplate等等。
JdbcTemplate开发步骤
- 导入spring-jdbc和spring-tx坐标
- 创建数据库表和实体
- 创建JdbcTemplate对象
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);- 执行数据库操作
更新操作:jdbcTemplate.update(sql,params)
查询操作:
jdbcTemplate.query(sql,Mapper,params)
jdbcTemplate.queryForObject(sql,Mapper,params)
Spring产生JdbcTemplate对象
可以将JdbcTemplate的创建权交给Spring,将数据源DataSource的创建权也交给Spring,在Spring容器内部将数据源DataSource注入到JdbcTemplate模板对象中,配置如下
<!-- 加载jdbc.properties -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 数据源对象-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- jdbc模板对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
Spring 练习
环境搭建
- 创建工程(Project&Module)
- 导入静态页面
- 导入需要坐标
- 创建包结构(controller service dao domain utils)
- 导入数据库脚本
- 创建POJO类
- 创建配置文件(applicationContext.xml, spring-mvc.xml , jdbc.properties, log4j.properties)
角色列表的展示和添加操作
角色列表的展示步骤分析:
- 点击角色管理菜单发送请求到服务器端(修改角色管理菜单的url地址)
- 创建RoleController和showList()方法
- 创建RoleService和showList()方法
- 创建RoleDao和findAll()方法
- 使用JdbcTemplate完成查询操作
- 将查询数据存储到Model中
- 转发到role-list.jsp页面进行展示
角色添加的步骤分析
- 点击列表页面新建按钮跳转到角色添加页面
- 输入角色信息,点击保存按钮,表单数据提交服务器
- 编写RoleController的save()方法
- 编写RoleService的save()方法
- 编写RoleDao的save()方法
- 使用JdbcTemplate保存Role数据到sys_role
- 跳转回角色列表页面
SpringMVC拦截器
拦截器的作用
- SpringMVC的拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。
- 将拦截器按一定的顺序联结成一条链,这条链称为拦截器链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。
拦截器和过滤器区别
- 使用范围
- 过滤器:是servlet规范中的一部分,任何Java Web工程都可以使用。
- 拦截器:是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用
- 拦截范围
- 过滤器:在url-pattern种配置了/*之后,可以对所有要访问的资源拦截
- 拦截器:只会拦截访问的控制器方法,如果访问的是jsp、html、css、image或者js是不会拦截的
自定义拦截器:
- 创建拦截器类实现HandlerInterceptor接口
- 配置拦截器
- 测试拦截器的拦截效果
拦截器方法说明
方法名 | 说明 |
---|---|
preHandle() | 方法将在请求处理之前进行调用,该方法的返回值是布尔值Boolean类型的,当它返回为false时,表示请求结束,后续的Interceptor和Controller都不会再执行;当返回值为true时就会继续调用下一个Interceptor的preHandle方法 |
postHandle() | 该方法是在当前请求进行处理之后被调用的,前提是preHandle方法的返回值为true时才能被调用,且它会在DispatcherServlet进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的ModelAndView对象进行操作 |
afterCompletion() | 该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行,前提是preHandle方法的返回值是true时才能被调用 |
SpringMVC异常处理
异常处理的思路:
- 系统中异常包括两类:预期异常和运行时异常,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发,测试等手段减少运行时异常的发生。
- 系统的Dao、Service、Controller出现都通过throws Exception向上抛出,最后由SpringMVC前端控制器交由异常处理器(HandlerExceptionResolver)处理异常。
异常处理两种方式
- 使用SpringMVC提供的简单异常处理器SimpleMappingExceptionResolver
SpringMVC已经定义好了该类型转换器,在使用时可以根据项目情况进行相应异常与视图的映射配置- 实现Spring的异常处理接口HandlerExceptionResolver自定义自己的异常处理器
① 创建异常处理器类实现HandlerExceptionResolver
② 配置异常处理器
③ 编写异常页面
④ 测试异常跳转
Spring的AOP
什么是AOP?
- AOP为Aspect Oriented Programming的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
- AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP的作用和优势
- 作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强
- 优势:减少重复代码,提高开发效率,并且便于维护
AOP的底层实现
- 实际上,AOP的底层是通过Spring提供的动态代理技术实现的。在运行期间,Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。
AOP的动态代理技术
- 常用的动态代理技术
- JDK代理:基于接口的动态代理技术
- cglib代理:基于父类的动态代理技术
AOP相关概念
- Spring的AOP实现底层就是对上面的动态代理的代码进行了封装,封装后我们只需要对需要关注的部分进行代码编写,并通过配置的方式完成指定目标的方法增强。
- Target(目标对象):代理的目标对象
- Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
- Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。(可以被增强的方法)
- Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义(实际增强了的那个方法)
- Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知
- Aspect(切面):是切入点和通知(引介)的结合
- Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入
AOP开发明确的事项
- 谁是切点(切点表达式配置)
谁是通知(切面类中的增强方法)
将切点和通知进行织入配置
需要编写的内容
① 编写核心业务代码(目标类的目标方法)
② 编写切面类,切面类中有通知(增强功能方法)
③ 在配置文件中,配置织入关系,即将哪些通知与哪些连接点进行结合AOP技术实现的内容
- Spring框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。
- AOP底层使用哪种代理方式:
- 在spring中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。
基于XML的AOP开发
快速入门
- 导入AOP相关坐标
- 创建目标接口和目标类(内部有切点)
- 创建切面类(内部有增强方法)
- 将目标类和切面类的对象创建全交给spring
- 在applicationContext.xml中配置织入关系
- 测试代码
通知的类型
- 通知的配置语法:
<aop:通知类型method=“切面类中方法名” pointcut=“切点表达式”></aop:通知类型>
名称&标签 | 说明 |
---|---|
前置通知 <aop:before> | 用于配置前置通知,指定增强的方法在切入点方法之前执行 |
后置通知 <aop:after-returning> | 用于配置后置通知,指定增强的方法在切入点方法之后执行 |
环绕通知 <aop:around> | 用于配置环绕通知,指定增强的方法在切入点方法之前和之后都执行 |
异常抛出通知 <aop:throwing> | 用于配置异常抛出通知,指定增强的方法在在出现异常时执行 |
最终通知 <aop:after> | 用于配置最终通知,无论增强方式执行是否有异常都会执行 |
- 切点表达式的抽取
- 当多个增强的切点表达式相同时,可以将切点表达式进行抽取,在增强中使用pointcut-ref属性代替pointcut属性来引用抽取后的切点表达式。
<aop:config>
<!--引用myAspect的Bean为切面对象-->
<aop:aspect ref="myAspect">
<aop:point id="myPointcut" execution(* com.itheima.aop.*.*(..))"/>
<aop:before method="before" pointcut-ref="myPointcut"></aop:before>
</aop:aspect>
</aop:config>
知识要点:
- aop织入的配置
<aop:config>
<aop:aspect ref="切面类">
<aop:before method="通知方法名称" pointcut="切点表达式"></aop:before>
</aop:aspect>
</aop:config>
- 通知的类型:前置通知、后置通知、环绕通知、异常抛出通知、最终通知
- 切点表达式的写法:
execution([修饰符]返回值类型 包名.类名.方法名(参数))
基于注解的AOP开发
- 快速入门
基于注解的aop开发步骤:
- 创建目标接口和目标类(内部有切点)
- 创建切面类(内部有增强方法)
- 将目标类和切面类的对象创建权交给spring
- 在切面类中使用注解配置织入关系
- 在配置文件中开启组件扫描和AOP的自动代理
- 测试
<!--组件扫描-->
<context:component-scan base-package="com.itheima.anno"/>
<!--aop自动代理-->
<aop:aspectj-autoproxy/>
- 注解配置AOP详解
- 注解通知的类型
通知的配置语法:@通知注解(“切点表达式”)
名称&标签 | 说明 |
---|---|
前置通知 @before | 用于配置前置通知,指定增强的方法在切入点方法之前执行 |
后置通知 @AfterReturning | 用于配置后置通知,指定增强的方法在切入点方法之后执行 |
环绕通知 @Around | 用于配置环绕通知,指定增强的方法在切入点方法之前和之后都执行 |
异常抛出通知 @AfterThrowing | 用于配置异常抛出通知,指定增强的方法在在出现异常时执行 |
最终通知 @After | 用于配置最终通知,无论增强方式执行是否有异常都会执行 |
- 切点表达式的抽取
同xml配置aop一样,我们可以将切点表达式抽取。抽取方式是在切面内定义方法,在该方法上使用@Pointcut注解定义切点表达式,然后再在增强注解中进行引用。具体如下:
@Component("myAspect")
@Aspect
public class MyAspect{
@Before("MyAspect.myPoint()")
public void before(){
System.out.println("前置代码增强...");
}
@Pointcut("execution(* com.itheima.aop.*.*(..))")
public void myPoint(){}
- 知识要点
- 注解aop开发步骤:
① 使用@Aspect标注切面类
② 使用@通知注解标注通知方法
③ 在配置文件中配置aop自动代理<aop:aspectj-autoproxy/>
- 通知注解类型
Spring的事务控制
- 编程式事务控制相关对象
- PlatformTransactionManager接口是spring的事务管理器,它里面提供了我们常用的操作事务的方法
- 注意:
PlatformTransactionManager是接口类型,不同的Dao层技术则有不同的实现类,例如:Dao层技术是jdbc或mybatis时:org.springframework.jdbc.DataSourceTransactionManager
方法 | 说明 |
---|---|
TransactionStatus getTransaction(TransactionDefination defination | 获取事务的状态信息 |
void commit(TransactionStatus status) | 提交事务 |
void rollback(TransactionStatus status) | 回滚事务 |
TransactionDefinition是事务的定义信息对象
- 设置事务隔离级别,可以解决事务并发产生的问题,如脏读、不可重复读和虚读。
- 事务传播行为
TranctionStatus接口提供的是事务具体运行状态
- 声明式事务控制
Spring的声明式事务控制就是采用声明的方式来处理事务。这里所说的声明,就是指在配置文件中声明,用在Spring配置文件中声明式的处理事务来代替代码式的处理事务。
底层是AOP思想
基于xml的声明式事务控制
配置要点:
- 平台事务管理器配置
- 事务通知的配置
- 事务aop织入的配置
基于注解的声明式事务控制
- 使用@Transaction在需要进行过事务控制的类或是方法上修饰,注解可用的属性同xml配置方式,例如隔离级别、传播行为等。
- 注解使用在类上,那么该类下的所有方法都使用同一套注解参数配置。
- 使用在方法上,不同的方法可以采用不同的事务参数配置。
- Xml配置文件中要开启事务的注解驱动
<tx:annotation-driven/>
配置要点:
- 平台事务管理器配置(xml方式)
- 事务通知的配置(@Transaction注解配置)
- 事务注解驱动的配置
<tx:annotation-driven>
Mybatis
Mybatis开发步骤:
- 添加MyBatis的坐标
- 创建user数据表
- 编写User实体类
- 编写映射文件UserMapper.xml
- 编写核心文件SqlMapConfig.xml
- 编写测试类
Mybatis执行更新操作,需要提交事务 commit
Mybatis的Dao层实现的两种方式
- 手动对Dao进行实现:传统开发方式
- 代理方式对Dao进行实现 (不需要写接口的实现类)
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);