观看课程为黑马程序员SSM框架教程|Spring+SpringMVC+MyBatis
点此观看
一、 Spring简介
1.1 Spring是什么
- Spring是分层的 Java SE/EE应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Control:反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核。
full-stack:和我们脑海中的全栈不太一样,我们脑海中的全栈是前端和服务端我们都去学,从头做到尾。Spring的全栈是各层都有对应的解决方案,外部层用SpringMVC,Dao层有JDBC模板,还有后期学的SpringDate的内容
- 提供了展现层 SpringMVC 和持久层 Spring JDBCTemplate 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE 企业应用开源框
1.2 Spring发展历程
1.3 Spring的优势
1)方便解耦,简化开发
通过 Spring 提供的 IoC容器,可以将对象间的依赖关系交由 Spring 进行控制,避免硬编码所造成的过度耦合。
用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
2)AOP 编程的支持
通过 Spring的 AOP 功能,方便进行面向切面编程,许多不容易用传统 OOP 实现的功能可以通过 AOP 轻松实现。
比如:安全、日志、代码集中式的处理,提高复用性,简化开发
3)声明式事务的支持
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务管理,提高开发效率和质量。
不用手动的写代码处理事务,只需要在spring的配置文件里面写一个标签,标签里面写一些属性,这样就可以处理事务
4)方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情
5)方便集成各种优秀框架
Spring对各种优秀框架(Struts、Hibernate、Hessian、Quartz等)的支持。
spring提供了对junit4的支持,里面有单独的模块就是整合junit,方便写spring程序的时候测试
6)降低 JavaEE API 的使用难度
Spring对 JavaEE API(如 JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些 API 的使用难度大为降低。
7)Java 源码是经典学习范例
Spring的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对Java 设计模式灵活运用以及对 Java技术的高深造诣。它的源代码无意是 Java 技术的最佳实践的范例
1.4 Spring的体系结构
Spring快速入门
2.1 Spring开发步骤
①导入spring对应的maven坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
②导入Dao的接口和实现类
③创建Spring核心配置文件(习惯命名为applicationContext)
④在Spring配置文件中配置UserDaoImpl
⑤使用Spring的API获得Bean实例
package com.itheima.demo;
import com.itheima.dao.UserDao;
import javafx.application.Application;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserDaoDemo {
public static void main(String[] args){
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao)app.getBean("userDao");
userDao.save();
}
}
Spring配置文件
3.1 Bean标签基本配置
用于配置对象交由Spring 来创建。
默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功。
基本属性:
id:Bean实例在Spring容器中的唯一标识
class:Bean的全限定名称
3.2 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实例
Bean的生命周期:
*对象创建:当应用加载,创建容器时,对象就被创建了
*对象运行:只要容器在,对象一直活着
*对象销毁:当应用卸载,销毁容器时,对象就被销毁了
2)当scope的取值为prototype时
Bean的实例化个数:多个
Bean的实例化时机:当调用getBean()方法时实例化Bean
*对象创建:当使用对象时创建新的对象实例
*对象运行:只要对象在使用中,就一直活着
*对象销毁:当对象长时间不用时,被java的垃圾回收器回收了
举个栗子:
测试核心代码:
//测试scope属性
public void test1(){
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao1 = (UserDao)app.getBean("userDao");
UserDao userDao2 = (UserDao)app.getBean("userDao");
System.out.println(userDao1);
System.out.println(userDao2);
}
(1)①当scope为singleton时,容器当中存在一个对象,测试结果地址相同
②当加载配置文件,创建spring容器时bean被创建
(2)当scope为prototype时,容器当中存在多个对象,测试结果地址不同
②每次getBean的时候创建一个bean
3.3Bean生命周期配置
init-method: 指定类中的初始化方法名称
destroy-method:指定类中销毁方法名称
在applicationContext.xml中配置:
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl" init-method="init" destroy-method="destroy"></bean>
小测试demo:
public void test1(){
//加载配置文件,创建spring容器
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao1 = (UserDao)app.getBean("userDao");
System.out.println(userDao1);
((ClassPathXmlApplicationContext)app).close();
}
注:ApplicationContext是接口,ClassPathXmlApplication是实现类,直接app.close()会发现没有close这个方法,强转为实现类后有该方法,也可以将其在创建的时候就改为实现类,如下:ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
3.4 Bean实例化三种方式
无参构造方法实例化
使用无参构造方法实例化
它会根据默认无参构造方法来创建类对象,如果bean中没有默认无参构造函数,将会创建失败
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
工厂静态方法实例化
工厂的静态方法返回Bean实例
public class StaticFactoryBean {
public static UserDao createUserDao(){
return new UserDaoImpl();
}
}
配置xml文件
<bean id="userDao" class="com.itheima.factory.StaticFactory" factory-method="getUserDao"></bean>
工厂实例方法实例化
工厂的非静态方法返回Bean实例
public class DynamicFactoryBean {
public UserDao createUserDao(){
return new UserDaoImpl();
}
}
配置xml文件
//spring创建工厂对象
<bean id="factory" class="com.itheima.factory.DynamicFactory"></bean>
//工厂当中工厂内部的方法去获得指定的对象
<bean id="userDao" factory-bean="factory" factory-method="getUserDao"></bean>
3.5Bean的依赖注入入门
①创建UserService,UserService 内部在调用 UserDao的save() 方法
public class UserServiceImpl implements UserService {
public void save() {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) app.getBean("userDao");
userDao.save();
}
}
②将UserServiceImpl的创建交给Spring
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl"/>
③从Spring容器中获得UserService进行操作
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) app.getBean("userService");
userService.save();
3.6 Bean的依赖注入分析
目前UserService实例和UserDao实例都存在于Spring容器中,当前的做法是在容器外部获得UserService实例和UserDao实例,然后在程序中进行结合。外部层用的是service,service需要调用dao
因为UserService和UserDao都在Spring容器中,而最终程序直接使用的是UserService,所以可以在Spring容器中,将UserDao设置到UserService内部。
怎么把这个数据设置到某个对象内部? 主要是两种方式,第一种方式是set方法,调用user service的setUserDao方法,第二种是构造,通过有参构造把某些对象注入到内部
3.7 Bean的依赖注入概念
依赖注入(Dependency Injection):它是 Spring 框架核心 IOC 的具体实现。
经过上述分析,service需要dao的依赖注入
在编写程序时,通过控制反转,把对象的创建交给了 Spring,但是代码中不可能出现没有依赖的情况。
IOC 解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法。
把service和dao的关系配到容器当中
那这种业务层和持久层的依赖关系,在使用 Spring 之后,就让 Spring 来维护了。
简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。
我们只需要获取业务层,最终也能操纵到dao层
将Userdao注入到userService内部的具体实现
1)set方法注入
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void save() {
userDao.save();
}
配置xml文件
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
代码写成这样后报空指针异常
此处userService是new的,不是从容器拿的,new的对象内部没有dao
p命名空间注入本质也是set方法注入,但比起上述的set方法注入更加方便,主要体现在配置文件中,如下:
首先,需要引入P命名空间:
xmlns:p="http://www.springframework.org/schema/p"
其次,需要修改注入方式
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl" p:userDao-ref="userDao"/>
2)构造方法注入
创建有参构造(一般有无参构造时还要再加一个有参构造)
private UserDao userDao;
public UserServiceImpl(UserDao userDao){
this.userDao = userDao;
}
配置Spring容器调用有参构造时进行注入
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>
property中ref、value、name的区别
点击查看
3.8Bean的依赖注入的数据类型
上面的操作,都是注入的引用Bean,除了对象的引用可以注入,普通数据类型,集合等都可以在容器中进行注入。
注入数据的三种数据类型
普通数据类型
引用数据类型
集合数据类型
其中引用数据类型,此处就不再赘述了,之前的操作都是对UserDao对象的引用进行注入的,下面将以set方法注入为
例,演示普通数据类型和集合数据类型的注入
1) 普通数据类型的注入
public class UserDaoImpl implements UserDao {
private String company;
private int age;
public void setCompany(String company) {
this.company = company;
}
public void setAge(int age) {
this.age = age;
}
public void save() {
System.out.println(company+"==="+age);
System.out.println("UserDao save method running....");
}
}
xml文件的配置
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
<property name="username" value="zhangsan"></property>
<property name="age" value="18"></property>
</bean>
2)集合数据类型(List)的注入
public class UserDaoImpl implements UserDao {
private List<String> strList;
public void setStrList(List<String> strList) {
this.strList = strList;
}
public void save() {
System.out.println(strList);
System.out.println("UserDao save method running....");
}
}
xml配置文件
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
<property name="strList">
<list>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</list>
</property>
</bean>
3)集合数据类型(List)的注入
public class UserDaoImpl implements UserDao {
private List<User> userList;
public void setUserList(List<User> userList) {
this.userList = userList;
}
public void save() {
System.out.println(userList);
System.out.println("UserDao save method running....");
}
}
xml文件配置
<bean id="u1" class="com.itheima.domain.User"/>
<bean id="u2" class="com.itheima.domain.User"/>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
<property name="userList">
<list>
<bean class="com.itheima.domain.User"/>
<bean class="com.itheima.domain.User"/>
<ref bean="u1"/>
<ref bean="u2"/>
</list>
</property>
</bean>
4)集合数据类型( Map<String,User> )的注入
public class UserDaoImpl implements UserDao {
private Map<String,User> userMap;
public void setUserMap(Map<String, User> userMap) {
this.userMap = userMap;
}
public void save() {
System.out.println(userMap);
System.out.println("UserDao save method running....");
}
}
xml文件的配置
<bean id="u1" class="com.itheima.domain.User"/>
<bean id="u2" class="com.itheima.domain.User"/>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
<property name="userMap">
<map>
<entry key="user1" value-ref="u1"/>
<entry key="user2" value-ref="u2"/>
</map>
</property>
</bean>
5)集合数据类型(Properties)的注入
public class UserDaoImpl implements UserDao {
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
public void save() {
System.out.println(properties);
System.out.println("UserDao save method running....");
}
}
xml文件配置
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
<property name="properties">
<props>
<prop key="p1">aaa</prop>
<prop key="p2">bbb</prop>
<prop key="p3">ccc</prop>
</props>
</property>
</bean>
3.9引入其他配置文件
实际开发中,Spring的配置内容非常多,这就导致Spring配置很繁杂且体积很大,所以,可以将部分配置拆解到其他
配置文件中,而在Spring主配置文件通过import标签进行加载
<import resource="applicationContext-xxx.xml"/>
小结
<bean>标签
id属性:在容器中Bean实例的唯一标识,不允许重复
class属性:要实例化的Bean的全限定名
scope属性:Bean的作用范围,常用是Singleton(默认)和prototype
<property>标签:属性注入
name属性:属性名称
value属性:注入的普通属性值
ref属性:注入的对象引用值
<list>标签
<map>标签
<properties>标签
<constructor-arg>标签
<import>标签:导入其他的Spring的分文件
4.Spring相关API
4.1ApplicationContext的继承体系
applicationContext:接口类型,代表应用上下文,可以通过其实例获得 Spring 容器中的 Bean 对象
紫色代表接口,浅绿色代表抽象类,深绿色是两个实现
4.2ApplicationContext的实现类
1)ClassPathXmlApplicationContext
它是从类的根路径下加载配置文件 推荐使用这种,因为使用这种的话路径永远正确,配置文件就放在resources目录下。
ApplicationContext app = new ClassPathXmlApplicationContetxt(“applicationContext.xml”);
2)FileSystemXmlApplicationContext
它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
ApplicationContext app = new FileSystemXmlApplicationContext(“C:\Users\applicationcontext.xml”);
3)AnnotationConfigApplicationContext
当使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。
4.3getBean()方法的使用
getBean()方法源码
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
public <T> T getBean(Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(requiredType);
}
其中,当参数的数据类型是字符串时,表示根据Bean的id从容器中获得Bean实例,返回是Object,需要强转。 当参数的数据类型是Class类型时,表示根据类型从容器中匹配Bean实例,当容器中相同类型的Bean有多个时,则此方法会报错。
使用情景
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>
<bean id="userService2" class="com.itheima.service.impl.UserServiceImpl">
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>
因为id具有唯一性,所以在获取的时候,能够区分开,如果现在容器中存在两个类型相同的 ,如以上代码,类型相同,如果再去执行的时候会报错,因为它不能区分到底是哪一个,如果容器中存在的某一类型的对象有多个的情况下,用id的方式,eg:UserService userService =
(UserService) app.getBean(UserService);如果某一类型的Bean只存在一个,通过类型的方式获取eg:UserService userService = app.getBean(UserService.class);
4.4知识要点
怎么创建对象?
三个API,目前主要用的是ApplicationContext app = new ClasspathXmlApplicationContext(“xml文件”);
怎么获取?
通过id
app.getBean(“id”)
通过类型
app.getBean(Class)
二、Ioc和DI注解开发
1.Spring配置数据源
1.1数据源(连接池)的作用及其开发步骤
作用
• 数据源(连接池)是提高程序性能如出现的
• 事先实例化数据源,初始化部分连接资源
• 使用连接资源时从数据源中获取
• 使用完毕后将连接资源归还给数据源
常见的数据源(连接池):DBCP、C3P0、BoneCP、Druid等,其作用都是一致的,只不过底层会对性能、API做一些修改
开发步骤
① 导入数据源的坐标和数据库驱动坐标
② 创建数据源对象
③ 设置数据源的基本连接数据
④ 使用数据源获取连接资源和归还连接资源
1.2 数据源的手动创建
①导入c3p0和druid的坐标
<!-- C3P0连接池 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- Druid连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
②创建C3P0连接池
public void test1() throws Exception {
//创建数据源
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//设置数据库连接参数
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/db0");
dataSource.setUser("root");
dataSource.setPassword("root");
//获得连接对象
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close(); //表面上的关闭,实际上是归还资源到我们的数据源当中
}
创建Druid连接池
@Test
//测试手动创建druid数据源
public void test2() throws SQLException {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/db0");
dataSource.setUsername("root");
dataSource.setPassword("root");
DruidPooledConnection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
测试手动创建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.setUser(username);
dataSource.setPassword(password);
Connection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
③提取jdbc.properties配置文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=root
④读取jdbc.properties配置文件创建连接池
@Test
public void testC3P0ByProperties() throws Exception {
//加载类路径下的jdbc.properties
ResourceBundle rb = ResourceBundle.getBundle("jdbc"); //相对于resources的路径
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(rb.getString("jdbc.driver"));
dataSource.setJdbcUrl(rb.getString("jdbc.url"));
dataSource.setUser(rb.getString("jdbc.username"));
dataSource.setPassword(rb.getString("jdbc.password"));
Connection connection = dataSource.getConnection();
System.out.println(connection);
}
1.3Spring配置数据源
可以将DataSource的创建权交由Spring容器去完成
DataSource有无参构造方法,而Spring默认就是通过无参构造方法实例化对象的
DataSource要想使用需要通过set方法设置数据库连接信息,而Spring可以通过set方法进行字符串注入
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--set方法去掉set改小写-->
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
</bean>
测试从容器当中获取数据源
ApplicationContext applicationContext = new
ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = (DataSource)
applicationContext.getBean("dataSource");
//app.getBean("DataSource.class"); //通过类来获取
Connection connection = dataSource.getConnection();
System.out.println(connection);
1.4抽取jdbc配置文件
applicationContext.xml加载jdbc.properties配置文件获得连接信息。
首先,需要引入context命名空间和约束路径:
命名空间:xmlns:context=“http://www.springframework.org/schema/context”
约束路径:http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
<?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/conetxt/spring-context.xsd">
<!--加载外部property文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--set方法去掉set改小写-->
<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>
</beans>
1.5知识要点
Spring容器加载properties文件
<context:property-placeholder location="xx.properties"/>
<property name="" value="${key}"/>
2.Spring注解开发
2.1Spring原始注解
Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置,文件可以简化配置,提高开发效率。
spring的原始注解和新注解主要是出现的时间不相同
Spring原始注解主要是替代的配置
@Component是组件,代替配置bean,@Controller、@Service、@Resposition其实就是@Component多了语义化
@PostConstruct、@PreDestory就相当于之前的initmethod、destorymethod
注意:
使用注解进行开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean
需要进行扫描以便识别使用注解配置的类、字段和方法。
<!--注解的组件扫描-->
<context:component-scan base-package="com.itheima"></context:component-scan>
使用@Compont或@Repository标识UserDaoImpl需要Spring进行实例化。
//@Component("userDao")
@Repository("userDao")
public class UserDaoImpl implements UserDao {
//xml方式set方法必须写,注解方式可省略
//public void setUserDao(UserDao userDao){
// this.userDao = userDao;
// }
@Override
public void save() {
System.out.println("save running... ...");
}
}
使用@Compont或@Service标识UserServiceImpl需要Spring进行实例化
使用@Autowired或者@Autowired+@Qulifier或者@Resource进行userDao的注入
//@Component("userService")
@Service("userService")
public class UserServiceImpl implements UserService {
/*@Autowired
@Qualifier("userDao")*/
@Resource(name="userDao")
private UserDao userDao;
@Override
public void save() {
userDao.save();
}
}
使用@Value进行字符串的注入
@Repository("userDao")
public class UserDaoImpl implements UserDao {
@Value("注入普通数据")
private String str;
@Value("${jdbc.driver}")
private String driver;
@Override
public void save() {
System.out.println(str);
System.out.println(driver);
System.out.println("save running... ...");
}
}
使用@Scope标注Bean的范围
//@Scope("prototype")
@Scope("singleton")
public class UserDaoImpl implements UserDao {
//此处省略代码
}
使用@PostConstruct标注初始化方法,使用@PreDestroy标注销毁方法
@PostConstruct
public void init(){
System.out.println("初始化方法....");
}
@PreDestroy
public void destroy(){
System.out.println("销毁方法.....");
}
使用上面的注解还不能全部替代xml配置文件,还需要使用注解替代的配置如下:
非自定义的Bean的配置:
加载properties文件的配置:context:property-placeholder
组件扫描的配置:context:component-scan
引入其他文件:
2.2Spring新注解
@Configuration
@ComponentScan
@Import
@Configuration
@ComponentScan("com.itheima")
@Import({DataSourceConfiguration.class})
public class SpringConfiguration {
}
@PropertySource
@value
@PropertySource("classpath:jdbc.properties")
public class DataSourceConfiguration {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
@Bean(name="dataSource")
public DataSource getDataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
return dataSource;
}
测试加载核心配置类创建Spring容器
@Test
public void testAnnoConfiguration() throws Exception {
ApplicationContext applicationContext = new
AnnotationConfigApplicationContext(SpringConfiguration.class);
UserService userService = (UserService)
applicationContext.getBean("userService");
userService.save();
DataSource dataSource = (DataSource)
applicationContext.getBean("dataSource");
Connection connection = dataSource.getConnection();
System.out.println(connection);
}
3.SpringMVC的组件解析
3.1 SpringMVC的执行流程
① 用户发送请求至前端控制器DispatcherServlet。
② DispatcherServlet收到请求调用HandlerMapping处理器映射器。
③ 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果
有则生成)一并返回给DispatcherServlet。
④ DispatcherServlet调用HandlerAdapter处理器适配器。
⑤ HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
⑥ Controller执行完成返回ModelAndView。
⑦ HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
⑧ DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
⑨ ViewReslover解析后返回具体View。
⑩ DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。DispatcherServlet响应用户。
3.2 SpringMVC组件解析
1. 前端控制器:DispatcherServlet
用户请求到达前端控制器,它就相当于 MVC 模式中的 C,DispatcherServlet 是整个流程控制的中心,由
它调用其它组件处理用户的请求,DispatcherServlet 的存在降低了组件之间的耦合性。
2. 处理器映射器:HandlerMapping
HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的
映射方式,例如:配置文件方式,实现接口方式,注解方式等。
3. 处理器适配器:HandlerAdapter
通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理
器进行执行。
4. 处理器:Handler
它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由
Handler 对具体的用户请求进行处理。
5. 视图解析器:View Resolver
View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名,即
具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
6. 视图:View
SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等。最
常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程
序员根据业务需求开发具体的页面
3.3. SpringMVC 组件解析
@RequestMapping
作用:用于建立请求 URL 和处理请求方法之间的对应关系
位置:
类上,请求URL 的第一级访问目录。此处不写的话,就相当于应用的根目录
方法上,请求 URL 的第二级访问目录,与类上的使用@ReqquestMapping标注的一级目录一起组成访问虚拟路径
属性:
value:用于指定请求的URL。它和path属性的作用是一样的
method:用于指定请求的方式
params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的key和value必须和配置的一模一样
例如:
params = {“accountName”},表示请求参数必须有accountName
params = {“moeny!100”},表示请求参数中money不能是100
3.3. SpringMVC 注解解析
- mvc命名空间引入
命名空间:xmlns:context=“http://www.springframework.org/schema/context”
xmlns:mvc=“http://www.springframework.org/schema/mvc”
约束地址:http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd- 组件扫描
SpringMVC基于Spring容器,所以在进行SpringMVC操作时,需要将Controller存储到Spring容器中,如果使
用@Controller注解标注的话,就需要使用<context:component-scan basepackage=“com.itheima.controller"/>进行组件扫描。
3.4 SpringMVC 组件解析
1. 视图解析器
SpringMVC有默认组件配置,默认组件都是DispatcherServlet.properties配置文件中配置的,该配置文件地址
org/springframework/web/servlet/DispatcherServlet.properties,该文件中配置了默认的视图解析器,如下:
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.I
nternalResourceViewResolver
翻看该解析器源码,可以看到该解析器的默认设置,如下:
REDIRECT_URL_PREFIX = “redirect:” --重定向前缀(地址变化 )
FORWARD_URL_PREFIX = “forward:” --转发前缀(默认值)
prefix = “”; --视图名称前缀
suffix = “”; --视图名称后缀
3. 4 SpringMVC 组件解析
- 视图解析器
我们可以通过属性注入的方式修改视图的的前后缀
<!--配置内部资源视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
3.5 知识要点
SpringMVC的相关组件
• 前端控制器:DispatcherServlet
• 处理器映射器:HandlerMapping
• 处理器适配器:HandlerAdapter
• 处理器:Handler
• 视图解析器:View Resolver
• 视图:View
SpringMVC的注解和配置
• 请求映射注解:@RequestMapping
• 视图解析器配置:
REDIRECT_URL_PREFIX = “redirect:”
FORWARD_URL_PREFIX = “forward:”
prefix = “”;
suffix = “”;
4.SpringMVC的请求和响应
1. SpringMVC的数据响应
1.1 SpringMVC的数据响应方式
1) 页面跳转
直接返回字符串
通过ModelAndView对象返回
2) 回写数据
直接返回字符串
返回对象或集合
1.2 页面跳转
-
返回字符串形式
直接返回字符串:此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转。
在这里插入图片描述
-
返回ModelAndView对象
@RequestMapping("/quick2")
public ModelAndView quickMethod2(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("redirect:index.jsp");
return modelAndView;
}
@RequestMapping("/quick3")
public ModelAndView quickMethod3(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("forward:/WEB-INF/views/index.jsp");
return modelAndView;
}
// springMVC框架提供modelAndView对象,并注入
@RequestMapping("/quick4")
public ModelAndView quickMethod4(ModelAndView modelAndView){
modelAndView.addObject("username", "itheima");
modelAndView.setViewName("sucess");
return modelAndView;
}
@RequestMapping("/quick5")
public ModelAndView quickMethod5(Model model){
model.setAttribute("username", "itheima");
return "success";
}
1.3 回写数据
- 直接返回字符串
Web基础阶段,客户端访问服务器端,如果想直接回写字符串作为响应体返回的话,只需要使用
response.getWriter().print(“hello world”) 即可,那么在Controller中想直接回写字符串该怎样呢?
① 通过SpringMVC框架注入的response对象,使用response.getWriter().print(“hello world”) 回写数
据,此时不需要视图跳转,业务方法返回值为void。
@RequestMapping("/quick4")
public void quickMethod4(HttpServletResponse response) throws
IOException {
response.getWriter().print("hello world");
}
② 将需要回写的字符串直接返回,但此时需要通过@ResponseBody注解告知SpringMVC框架,方法
返回的字符串不是跳转是直接在http响应体中返回。
@RequestMapping("/quick5")
@ResponseBody
public String quickMethod5() throws IOException {
return "hello springMVC!!!";
}
没有@ResponseBody的话区分不清楚是要回写还是要跳转页面(逻辑视图名),报错类型为找不到对应资源