企业级开发框架——SSM
SSM = springmvc + spring + mybatis
框架
框架就是一套规范,既然是规范,你使用这个框架就要遵守这个框架所规定的约束。
框架可以理解为半成品软件,框架做好以后,接下来在它基础上进行开发。
框架为我们封装好了一些冗余,且重用率低的代码。并且使用反射与动态代理机制,将代码实现了通用性,让开发人员把精力专注在核心的业务代码实现上。
三层架构:
软件开发常用三级架构,每层有清晰的任务划分:
-
持久层(dao):主要完成与数据库相关的操作,
持久层框架:专注于解决数据持久化的框架。常用的有mybatis、hibernate、spring jdbc等等 -
业务层(service):主要根据功能需求完成业务逻辑的定义与实现;
-
表现层(web/view):主要完成与最终软件使用用户的交互;
表现层框架:专注于解决与用户交互的框架。常见的有struts2、spring mvc等等全栈框架: 能在各层都给出解决方案的框架。比较著名的就是spring。
三层架构之间调用关系为:表现层调用业务层,业务层调用持久层。
Mybatis
MyBatis是一个优秀的基于ORM的半自动轻量级持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码
对比:
原始jdbc操作:
存在问题:
①数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能
② sql语句在代码中存在硬编码,耦合太重,造成代码不易维护
③ 查询操作时,需要手动将结果集中的数据手动封装到实体中。
应对上述问题给出的解决方案:
① 使用数据库连接池初始化连接资源
② 将sql语句抽取到xml配置文件中
③ 使用反射、内省等底层技术,自动将实体与表进行属性与字段的自动映射
ORM思想
ORM(Object Relational Mapping)对象关系映射
- O(对象模型):
实体对象,即我们在程序中根据数据库表结构建立的一个个实体javaBean - R(关系型数据库的数据结构):
关系数据库领域的Relational(建立的数据库表) - M(映射):
从R(数据库)到O(对象模型)的映射,可通过XML文件映射
实现:
(1)让实体类和数据库表进行一一对应关系
先让实体类和数据库表对应
再让实体类属性和表里面字段对应
(2)不需要直接操作数据库表,直接操作表对应的实体类对象
** 一个实体对应一张表;一个对象对应一条记录**
mybatis采用ORM思想解决了实体和数据库映射的问题,对jdbc 进行了封装,屏蔽了jdbc api 底层访问细节,使我们不用与jdbc api 打交道,就可以完成对数据库的持久化操作
Mybatis代码实现
1,相关依赖
<!--mybatis坐标-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
<!--mysql驱动坐标-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
<scope>runtime</scope>
</dependency>
<!--单元测试坐标-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
2,mybatis映射文件,配置了sql语句
<?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="UserMapper">
<!--查询所有-->
<select id="findAll" resultType="com.dong.domain.User">
select * from user
</select>
</mapper>
映射文件概述
3,mybatis核心配置文件,配置了数据源、事务等数据库相关信息
<?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="mysql">
<!--使用MySQL环境-->
<environment id="mysql">
<!--使用JDBC类型事务管理器-->
<transactionManager type="JDBC"></transactionManager>
<!--使用连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver">
</property>
<property name="url" value="jdbc:mysql:///mybatis_db">
</property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</dataSource>
</environment>
</environments>
<!--加载映射配置-->
<mappers>
<mapper resource="com/dong/mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
核心配置解析
代理开发方式
采用 Mybatis 的基于接口代理方式实现 持久层 的开发,这种方式是企业的主流。
基于接口代理方式的开发只需要程序员编写 Mapper 接口,Mybatis 框架会为我们动态生成实现类的对象。
这种开发方式要求我们遵循一定的规范:
- Mapper.xml映射文件中的namespace与mapper接口的全限定名相同
- Mapper接口方法名和Mapper.xml映射文件中定义的每个statement的id相同
- Mapper接口方法的输入参数类型和mapper.xml映射文件中定义的每个sql的parameterType的类型相同
- Mapper接口方法的输出参数类型和mapper.xml映射文件中定义的每个sql的resultType的类型相同
Mybatis基于接口代理方式的内部执行原理
我们的持久层现在只有一个接口,而接口是不实际干活的,那么是谁在做查询的实际工作呢?追踪源码:
1 我们使用的mapper实际上是一个代理对象,是由MapperProxy代理产生的。
2 追踪MapperProxy的invoke方法会发现,其最终调用了mapperMethod.execute(sqlSession, args)
3 进入execute方法会发现,最终工作的还是sqlSession
Spring
Spring是分层的 Java SE/EE应用 full-stack(全栈式) 轻量级开源框架
提供了持久层 Spring JDBC Template、业务层 事务管理、表现层 SpringMVC等众多的企业级应用技术,能整合开源的众多著名的第三方框架和类库,逐渐成为使用最多的Java EE 企业应用开源框架。
-
全栈式:它对各种主流技术和框架都进行了整合,同时对三层架构都提供解决方案
-
轻量级:轻/重量级,主要依据是,使用了多少服务,启动时需要加载的资源多少以及耦合度等
两大核心:
** IOC** 控制反转,把对象的创建权交给Spring
** AOP **面向切面编程,动态代理 ,在不修改源码的情况下对代码进行增强
Spring优势:
1,方便解耦
- Spring就是一个容器,可以将所有对象创建和关系维护交给Spring管理
耦合:对象之间的关联性,程序之间的依赖关系,解耦:降低程序之间的依赖关系。有new就会存在编译期依赖。如何去掉new?
解耦思路:配置文件+反射
编译期依赖,耦合重的体现。做到编译期不依赖, 运行期依赖
2,AOP编程的支持
-
Spring提供面向切面编程,方便实现程序进行权限拦截,运行监控等功能。
在不修改源码的情况下,对代码进行增强
3,声明式事务的支持
- 通过配置完成事务的管理,无需手动编程
4,方便测试,降低JavaEE API的使用
- Spring对Junit4支持,可以使用注解测试 ,
5,方便集成各种优秀框架
- 不排除各种优秀的开源框架,内部提供了对各种优秀框架的直接支持
IOC
控制反转:是一种设计思想,指导我们设计出更加松耦合的程序
控制:在java中指的是对象的控制权限(创建、销毁)
反转:指的是对象控制权由原来 由开发者在类中手动控制 反转到 由Spring容器控制
自定义IOC容器,实现Service层与Dao层解耦
Spring开发基本坐标:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
Spring核心配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="com.lagou.dao.impl.UserDaoImpl"></bean>
</beans>
使用spring相关API获得Bean实例
public class UserTest {
@Test
public void testSave() throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.save();
}
}
Spring相关API
BeanFactory
BeanFactory是 IOC 容器的核心接口,它定义了IOC的基本功能。
特点:在第一次调用getBean()方法时,创建指定对象的实例
ApplicationContext
代表应用上下文对象,可以获得spring中IOC容器的Bean对象。
特点:在spring容器启动时,加载并创建所有对象的实例
Spring配置文件
Bean标签基本配置:
<bean id="" class=""></bean>
* 用于配置对象交由Spring来创建。
* 基本属性:
id:Bean实例在Spring容器中的唯一标识
class:Bean的全限定名
* 默认情况下它调用的是类中的 无参构造函数,如果没有无参构造函数则不能创建成功。
依赖注入DI
它是 Spring 框架核心 IOC 的具体实现。
通过控制反转,把对象的创建交给了 Spring,IOC 解耦只是降低他们的依赖关系,但不会消除。这种业务层和持久层的依赖关系,在使用 Spring 之后,就让 Spring 来维护了,就是通过框架把持久层对象传入业务层,而不用我们自己去获取。
- Spring重点配置
<bean>标签:创建对象并放到spring的IOC容器
id属性:在容器中Bean实例的唯一标识,不允许重复
class属性:要实例化的Bean的全限定名
scope属性:Bean的作用范围,常用是Singleton(默认)和prototype
<constructor-arg>标签:属性注入
name属性:属性名称
value属性:注入的普通属性值
ref属性:注入的对象引用值
<property>标签:属性注入
name属性:属性名称
value属性:注入的普通属性值
ref属性:注入的对象引用值
<list>
<set>
<array>
<map>
<props>
<import>标签:导入其他的Spring的分文件
Spring常用注解
注解 | 说明 |
---|---|
@Component | 使用在类上用于实例化Bean |
v@Configuration | 用于定义配置类,保证了配置类的内部方法之间依赖调用时都从容器中获取bean.避免了多例的出现 |
@Controller | 使用在web层类上用于实例化Bean |
@Service | 使用在service层类上用于实例化Bean |
@Repository | 使用在dao层类上用于实例化Bean |
@Autowired | 使用在字段上用于根据类型依赖注入 |
@Qualifier | 结合@Autowired一起使用,根据名称进行依赖注入 |
@Resource | 相当于@Autowired+@Qualifier,按照名称进行注入 (JDK11以后完全移除了javax扩展导致不能使用@resource注解,需要maven引入依赖) |
@Value | 注入普通属性 |
@Scope | 标注Bean的作用范围 |
引入依赖: |
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
配置组件扫描:
作用是指定哪个包及其子包下的Bean需要进行扫描以便识别使用注解配置的类、字段和方法。
<!--注解的组件扫描-->
<context:component-scan base-package="com.dong"></context:component-scan>
基于注解的Spring核心配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w1.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/context/spring-context.xsd">
<!--注解的组件扫描-->
<context:component-scan base-package="com.lagou"></context:component-scan>
<!--加载jdbc配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--把数据库连接池交给IOC容器-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--把QueryRunner交给IOC容器-->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>
</beans>
Spring整合Junit进行 测试
步骤分析:
1. 导入spring集成Junit的坐标
2. 使用@Runwith注解替换原来的运行器
3. 使用@ContextConfiguration指定配置文件或配置类
4. 使用@Autowired注入需要测试的对象
5. 创建测试方法进行测试
@RunWith(SpringJUnit4ClassRunner.class)
//@RunWith指定JUnit的运行环境,SpringJUnit4ClassRunner是spring提供的作为JUnit运行环境的类
@ContextConfiguration(classes = {SpringConfig.class})
public class SpringJunitTest {
@Autowired
private AccountService accountService;
//测试查询
@Test
public void testFindById() {
Account account = accountService.findById(3);
System.out.println(account);
}
}
AOP
AOP:面向切面编程 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高
程序的可重用性,同时提高了开发的效率。
这样做的好处是:
- 在程序运行期间,在不修改源码的情况下对方法进行功能增强
- 逻辑清晰,开发核心业务的时候,不必关注增强业务的代码
- 减少重复代码,提高开发效率,便于后期维护
AOP底层实现
AOP 的底层是通过 Spring 提供的的动态代理技术实现的。在运行期间,Spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。
动态代理技术
JDK代理:
基于接口的动态的代理技术,利用拦截器(必须实现invocationHandler)加上反射机制生成 一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理,从而实现方法增强
CGLib代理:
基于父类的动态代理技术:动态生成一个要代理的子类,子类重写要代理的类的所有不是 final的方法。在子类中采用方法拦截技术拦截所有的父类方法的调用,顺势织入横切逻辑,对方法进行增强
AOP相关术语
Spring 的 AOP 实现底层就是对动态代理的代码进行了封装,封装后我们只需要对需要关注的部分进行代码编写,并通过配置的方式完成指定目标的方法增强。常用的术语如下:
* Target(目标对象):代理的目标对象
* Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类
* Joinpoint(连接点):所谓连接点是指那些可以被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
* Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
* Advice(通知/ 增强):增强的业务逻辑,所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。分类:前置、后置、异常、最终通知,环绕通知:Spring提供的一种可以通过代码的方法手动控制通知的类型
`当前四个通知组合在一起时,执行顺序如下: @Before -> @After -> @AfterReturning(如果有异常:@AfterThrowing)`
* Aspect(切面):是切入点和通知(引介)的结合
* Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入
AOP快速入门(代码实现)
步骤分析:
1. 创建java项目,导入AOP相关坐标
2. 创建目标接口和目标实现类(定义切入点)
3. 创建通知类及方法(定义通知)
4. 将目标类和通知类对象创建权交给spring
5. 在核心配置文件中配置织入关系,及切面
6. 编写测试代码
需要的依赖:
<dependencies>
<!--导入spring的context坐标,context依赖aop-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- aspectj的织入(切点表达式需要用到该jar包) -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<!--spring整合junit-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
在核心配置文件中配置植入关系、切面
<?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: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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--目标类交给IOC容器-->
<bean id="accountService" class="com.lagou.service.impl.AccountServiceImpl"></bean>
<!--通知类交给IOC容器-->
<bean id="myAdvice" class="com.lagou.advice.MyAdvice"></bean>
<aop:config>
<!--引入通知类-->
<aop:aspect ref="myAdvice">
<!--配置目标类的transfer方法执行时,使用通知类的before方法进行前置增强-->
<aop:before method="before" pointcut="execution(public void
com.lagou.service.impl.AccountServiceImpl.transfer())"></aop:before>
</aop:aspect>
</aop:config>
</beans>
配置详解:
* aop织入的配置
<aop:config>
<aop:aspect ref=“通知类”>
<aop:before method=“通知方法名称” pointcut=“切点表达式"></aop:before>
</aop:aspect>
</aop:config>
* 通知的类型
前置通知、后置通知、异常通知、最终通知
环绕通知
* 切点表达式
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
JdbcTemplate
JdbcTemplate是spring框架中提供的一个模板对象,是对原始繁琐的Jdbc API对象的简单封装。
原方式:注册驱动 获取连接 获取预编译对象 执行sql 手动封装结果集
核心对象的创建:通过有参构造传入数据源对象:new JdbcTemplate(DataSource dataSource)
Spring整合 JDBBCTemplate
-
在Dao实现类里创建jdbcTemplate
@Autowired private JdbcTemplate jdbcTemplate;
-
调用jdbcTemplate的方法
-
编写AccountService接口和实现类,在Service实现类里注入Dao实例
@Autowired private AccountDao accountDao;
-
在配置文件xml中配置 JDBCTemplate实例
<!--把JdbcTemplate交给IOC容器-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
</bean>
Spring的事务
Spring的事务控制可以分为编程式事务控制和声明式事务控制。
声明式事务:开发者采用配置的方式来实现的事务控制,业务代码与事务代码实现解耦合,使用的AOP思想。
事务隔离级别
* ISOLATION_DEFAULT 使用数据库默认级别
* ISOLATION_READ_UNCOMMITTED 读未提交
* ISOLATION_READ_COMMITTED 读已提交
* ISOLATION_REPEATABLE_READ 可重复读
* ISOLATION_SERIALIZABLE 串行化
配置文件中实现
<!--事务管理器交给IOC-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
Spring集成web环境
问题:应用上下文对象是通过 new ClasspathXmlApplicationContext(spring配置文件) 方式获取的,但 是每次从容器中获得Bean时都要编写 new ClasspathXmlApplicationContext(spring配置文件) , 这样的弊端是配置文件加载多次,应用上下文对象创建多次。
解决:在Web项目中,可以使用ServletContextListener监听Web应用的启动,我们可以在Web应用启动时,就加载Spring的配置文件,创建应用上下文对象ApplicationContext,在将其存储到最大的域 servletContext域中,这样就可以在任意位置从域中获得应用上下文ApplicationContext对象了。
Spring提供了一个监听器ContextLoaderListener就是对上述功能的封 装,该监听器内部加载Spring配置文件,创建应用上下文对象,并存储到ServletContext域中,提供了一个客户端工具WebApplicationContextUtils供使用者获得应用上下文对象。
1,导入Spring集成web的坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.5.RELEASE</version>
2,在web.xml中配置监听器
<!--全局参数-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>•
</context-param>
<!--Spring的监听器-->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
3,Servlet通过工具获得应用上下文对象
ApplicationContext applicationContext =
WebApplicationContextUtils.getWebApplicationContext(servletContext);
Object obj = applicationContext.getBean("id");
SpringMVC
MVC是软件工程中的一种软件架构模式,它是一种分离业务逻辑与显示界面的开发思想.
* M(model)模型:处理业务逻辑,封装实体
* V(view) 视图:展示内容
* C(controller)控制器:负责调度分发(1.接收请求、2.调用模型、3.转发到视图)
SpringMVC 是一种基于 Java 的实现 MVC 设计模式的轻量级 Web 框架,SpringMVC 已经成为目前最主流的MVC框架之一,并且随着Spring3.0 的发布,全面超越 Struts2,成为最优秀的 MVC 框架。它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持 RESTful 编程风格的请求.
SpringMVC的框架就是封装了原来Servlet中的共有行为;例如:参数封装,视图转发等
SpringMVC quickstart
步骤分析:
1. 创建web项目,导入SpringMVC相关坐标
2. 配置SpringMVC前端控制器 DispathcerServlet
3. 编写Controller类和视图页面
4. 使用注解配置Controller类中业务方法的映射地址
5. 配置SpringMVC核心文件 spring-mvc.xml
- 相关依赖
<!-- 设置为web工程 -->
<packaging>war</packaging>
<dependencies>
<!--springMVC坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--servlet坐标-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--jsp坐标-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
- 配置SpringMVC前端控制器DispathcerServlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<!--前端控制器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 配置SpringMVC核心文件spring-mvc.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--配置注解扫描-->
<context:component-scan base-package="com.lagou.controller"/>
</beans>
Web工程执行流程
SpringMVC的执行流程
1. 用户发送请求至前端控制器DispatcherServlet。
2. DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3. 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如
果有则生成)一并返回给DispatcherServlet。
4. DispatcherServlet调用HandlerAdapter处理器适配器。
5. HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
6. Controller执行完成返回ModelAndView。
7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9. ViewReslover解析后返回具体View。
10. DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11. DispatcherServlet将渲染后的视图响应响应用户。
SpringMVC组件解析
*** 笔试题:SpringMVC中的三大组件?
- 处理器映射器:HandlerMapping/ 处理器适配器:HandlerAdapter/视图解析器:View Resolver
*** (四大组件+前端控制器)
1. 前端控制器:DispatcherServlet
- 整个流程控制的中心,由它调用其他组件处理用户请求,降低了组件之间的耦合性
用户请求到达前端控制器,它就相当于 MVC 模式中的 C,DispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,DispatcherServlet 的存在降低了组件之间的耦合性。
2. 处理器映射器:HandlerMapping
- 找处理器,返回链表
HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
3. 处理器适配器:HandlerAdapter
- 对处理器执行前进行适配
通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
4. 处理器:Handler
- 自己所编写的Controller.java,具体执行业务逻辑
它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到Handler。由Handler 对具体的用户请求进行处理。
5. 视图解析器:ViewResolver
- 对返回的逻辑视图名进行解析,生成view视图对象
View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名,即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
6. 视图:View 【**开发者编写**】
SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等。最常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
<!--配置注解扫描-->
<context:component-scan base-package="com.lagou.controller"/>
<!--处理器映射器和处理器适配器功能增强-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
SpringMVC注解解析
@Controller
SpringMVC基于Spring容器,所以在进行SpringMVC操作时,需要将Controller存储到Spring容器中,如果使用@Controller注解标注的话,就需要使用:
<!--配置注解扫描-->
<context:component-scan base-package="com.lagou.controller"/>
@RestController注解相当于@ResponseBody + @Controller合在一起的作用
返回json数据不需要在方法前面加@ResponseBody注解了,但使用@RestController这个注解,就不能返回jsp,html页面,视图解析器无法解析jsp,html页面
使用 @Controller 注解,在对应的方法上,视图解析器可以解析return 的jsp,html页面,并且跳转到相应页面
@RequestMapping
* 作用:
用于建立请求 URL 和处理请求方法之间的对应关系
* 位置:
1.类上:请求URL的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。
它出现的目的是为了使我们的URL可以按照模块化管理:
2.方法上:请求URL的第二级访问目录,和一级目录组成一个完整的 URL 路径。
* 属性:
1.value:用于指定请求的URL。它和path属性的作用是一样的
2.method:用来限定请求的方式
3.params:用来限定请求参数的条件
例如:params={"accountName"} 表示请求参数中必须有accountName
params={"money!100"} 表示请求参数中money不能是100
** @RequestBody** :该注解用于Controller的方法的形参声明,当使用ajax提交并指定contentType为json形式时,通过HttpMessageConverter接口转换为对应的POJO对象。
@ResponseBody:该注解用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端
SpringMVC的请求
客户端请求参数的格式是: name=value&name=value……
相关注解
@RequestParam
当请求的参数name名称与Controller的业务方法参数名称不一致时,就需要通过@RequestParam注解显示的绑定
eg:
<a href="${pageContext.request.contextPath}/user/findByPage?pageNo=2">
分页查询
</a>
/*
@RequestParam() 注解
defaultValue 设置参数默认值
name 匹配页面传递参数的名称
required 设置是否必须传递参数,默认值为true;如果设置了默认值,值自动改为false
*/
@RequestMapping("/findByPage")
public String findByPage(@RequestParam(name = "pageNo", defaultValue = "1")Integer pageNum, @RequestParam(defaultValue = "5") Integer pageSize) {
System.out.println(pageNum);
System.out.println(pageSize);
return "success";
}
@RequestHeader
获取请求头的数据。
public String requestHead(@RequestHeader("cookie") String cookie) {
@CookieValue
获取cookie中的数据。
public String cookieValue(@CookieValue("JSESSIONID") String jesessionId) {
SpringMVC的响应
响应方式:
页面跳转
- 返回字符串逻辑视图
- void原始ServletAPI
- ModelAndView
返回数据 - 直接返回字符串数据
- 将对象或集合转为json返回(任务二演示)
转发与重定向
请求转发,一次请求,且地址栏不发生改变
企业开发我们一般使用返回字符串逻辑视图实现页面的跳转,这种方式其实就是请求转发 forward转发
如果用了forward:则路径必须写成实际视图url,不能写逻辑视图。
使用请求转发,既可以转发到jsp,也可以转发到其他的控制器方法。
Redirect重定向
我们可以不写虚拟目录,springMVC框架会自动拼接,并且将Model中的数据拼接到url地址上
@SessionAttributes
如果在多个请求之间共用数据,则可以在控制器类上标注一个 @SessionAttributes,配置需要在
session中存放的数据范围,Spring MVC将存放在model中对应的数据暂存到 HttpSession 中。
注意:@SessionAttributes只能定义在类上
Restful
Restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服务器交互类的软件,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存机制等。
Restful风格的请求是使用“url+请求方式”表示一次请求目的,HTTP 协议里面四个表示操作方式的动词如下:
GET:读取(Read)
POST:新建(Create)
PUT:更新(Update)
DELETE:删除(Delete)
Restful代码实现
@PathVariable
用来接收RESTful风格请求地址中占位符的值
@RestController
RESTful风格多用于前后端分离项目开发,前端通过ajax与服务器进行异步交互,我们处理器通常返回的是json数据所以使用@RestController来替代@Controller和@ResponseBody两个注解。
SpringMVC异常处理
系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,
自定义异常处理器
1. 创建异常处理器类实现HandlerExceptionResolver
2. 配置异常处理器
3. 编写异常页面
4. 测试异常跳转
@Component
public class GlobalExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,HttpServletResponse response, Object handler, Exception ex) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("error", ex.getMessage());
modelAndView.setViewName("error");
return modelAndView;
}
}
<bean id="globalExecptionResovler" class="com.dong.exception.GlobalExecptionResovler"></bean>
拦截器interceptor
作用
Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(InterceptorChain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。
拦截器和过滤器区别
自定义拦截器:
创建拦截器类实现HandlerInterceptor接口
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--对哪些资源执行拦截操作-->
<mvc:mapping path="/**"/>
<bean class="com.lagou.interceptor.MyInterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
拦截器中的方法: