一、Mybatis
1.概述
MyBatis是对JDBC进行了简单的封装,帮助用户进行SQL参数的自动化映射,以及结果集与Java对象的映射。与Hibernate相比,更加配置简单、灵活、执行效率高。但是正因为此,所以没有实现完全自动化,需要手写SQL,这是优点也是缺点。由于SQL可见的,可以根据业务来进行优化。因此,对性能要求较高的电商类项目,一般会使用MyBatis,而对与业务逻辑复杂,对执行效率要求不高的传统行业,一般会使用Hibernate。
2.特点
Mybatis:
1) 支持自定义SQL、存储过程、及高级映射
2) 实现自动对SQL的参数设置
3) 实现自动对结果集进行解析和封装
4) 通过XML或者注解进行配置和映射
5) 实现Java对象与数据库表的映射转换
3.架构
MyBatis架构总结:
1.两种配置文件
a) mybatis-config.xml 是MyBatis的全局配置文件,包含全局配置信息,如数据库连接参数、插件等。整个框架中只需要一个即可。
b) xxxMapper.xml 是映射文件,里面配置了要执行的SQL语句,每个SQL对应一个Statement,可以有多个Mapper.xml文件,用namespace名称空间和SQL上的ID来唯一标识一个SQL语句。
2.框架执行流程
- 首先会通过SqlSessionFactoryBuilder来加载配置文件mybatis-config.xml和mapper.xml,生成一个SqlSessionFactory,加载mapper.xml的时候,顺便会对Sql进行编译,形成statement执行对象。
- 通过SqlSessionFactory建立连接,获取SqlSession对象
- MyBatis获取要执行的statement,进行自动参数设置
- SqlSession底层会通过Executor(执行器)来执行编译好的Statement,实现CRUD,获取结果
3.SQL的输入参数类型
a) POJO,普通Java对象
b) HashMap,其实是POJO的Map形式, 键值对就是对象字段名和值
c) 各种基本数据类型
4. SQL查询结果的输出形式
a) POJO,普通Java对象
b) HashMap,其实是POJO的Map形式, 键值对就是对象字段名和值
c) 各种基本数据类型
4.一些需要注意的点
映射文件中$ 和 # 区别:
#是占位符,编译时是?号
¥是SQL拼接,一般用于修改表名或者拼接like语句,可能会引发SQL注入问题
动态代理约定
约定namespace必须与DAO接口的全名称一致
约定statement的ID必须和接口中的方法名称一致
每一个dao接口 都有一个对应的 XxxMapper.xml映射文件(必须)
statement中定义的resultType必须和方法定义的返回值类型一致(必须)
5.mybatis-config.xml 全文配置文件详解
注意: 配置文件中的标签的顺序非常重要. 必须严格按照上述顺序!
5.1 properties 属性
作用:指定外部配置文件的位置
5.2 settings属性
调整 settings 中的设置是非常关键的,它们会改变 MyBatis 的运行时行为。
设置参数 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 该配置影响的所有映射器中配置的缓存的全局开关。 | true | false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。特定关联关系中可通过设置fetchType 属性来覆盖该项的开关状态。 | true | false | false |
aggressiveLazyLoading | 当启用时,带有延迟加载属性的对象的加载与否完全取决于对任意延迟属性的调用;反之,每种属性将会按需加载。 | true | false | true |
mapUnderscoreToCamelCase | 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。 | true | false | False |
5.3 typeAliases 类型别名
类型别名是为 Java 类型命名的一个短的名字。它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余。
例如:
mybatis-config.xml
<typeAliases>
<!--起别名-->
<typeAlias type="cn.domain.User" alias="User"/>
</typeAliases>
UserMapper.xml 可以将 cn.domain.User 替换成 User, 如下
<select id="queryUserById" parameterType="java.lang.Long" resultType="User">
select * from tb_user where id=#{id}
</select>
<select id="queryUserList" resultType="User">
select * from tb_user
</select>
问题: 如果有很多javabean,这样起别名太麻烦了?
解决方案: 指定包, 这样会将每个类的名称作为别名,如下
mybatis-config.xml
<typeAliases>
<!--起别名-->
<!--<typeAlias type="cn.domain.User" alias="User"/>-->
<!--指定包-->
<package name="cn.domain"/>
</typeAliases>
5.4 映射器(mappers)
配置扫描包
自动扫描配置包下的映射器
<!--关联映射文件-->
<mappers>
<!--方式三: 扫描包-->
<package name="cn.d_mapper"/>
</mappers>
要求: 1. 目录名和包名一致; 2. 文件名和接口名一致.
6.Mapper.xml映射文件详解
6.1 Select
进行查询的Statement
属性 | 描述 |
---|---|
id | 在命名空间中唯一的标识符,可以被用来引用这条语句。 |
parameterType | 将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset。 |
resultType | 从这条语句中返回的期望类型的类的完全限定名或别名。注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身。使用 resultType 或 resultMap,但不能同时使用。 |
resultMap | 外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,对其有一个很好的理解的话,许多复杂映射的情形都能迎刃而解。使用 resultMap 或 resultType,但不能同时使用。 |
6.2 insert update delete
常用属性:
id:这个statement的唯一标识
parameterType:输入参数类型,可选参数,mybatis可以自动推断数据类型
insert语句实现ID回填
<!--
useGeneratedKeys : 是否开启自增主键的回显功能
keyProperty: 对应javabean的属性名
keyColumn : 对应数据库的列名
-->
<insert id="inserUser" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
insert into tb_user(
id,
user_name,
password,
name,
age,
sex,
birthday,
created,
updated
)
values(
null,
#{userName},
#{password},
#{name},
#{age},
#{sex},
#{birthday},
now(),
now()
)
</insert>
6.3 #{}的用法
在Mapper.xml映射文件中,经常使用#{属性名} 来作为SQL语句的占位符,来映射Sql需要的实际参数,#{}就是一个预编译的占位符作用。
有几种情况:
1.如果只有一个参数
参数是基本数据类型:#{}中写什么都无所谓,MyBatis会把实际参数直接传入这个位置,不管参数名称和类型。
参数是自定义POJO或者HashMap类型:MyBatis会把User对象中的属性名和属性值以键值对形式保存到一个类似Map的结构中。当我们用#{属性名} 来取值时,其实就相当于根据键查找值。可以直接获取到User的属性值!
2.如果有多个参数
默认情况下,我们可以通过#{0} 或 #{param1} 来取到第一个参数,以此类推。
推荐方法:使用@Param注解来指定参数名称,代码可读性好!
6.4 ${}的用法
无论是1个参数,还是多个参数,都使用@Param注解,然后通过注解的中指定的名称取值
7.ResultMap的高级映射
ResultMap用来定义SQL查询的结果与Java对象的映射关系。
ResultMap实例:
<resultMap id="userResultMap" type="User">
<!--
property: javabean对应的属性
column : 数据库对应的列名
-->
<id property="id" column="id"></id>
<result property="userName" column="user_name"/>
</resultMap>
<!--
select元素:代表查询,类似的还有update、insert、delete
id:这个statement的唯一标示
parameterType:输入参数类型,可选参数,mybatis可以自动推断数据类型
resultType:查询结果类型,如果结果是集合,请写集合内元素类型!
resultMap:结果集映射,这个和resultType 只能存在1个,应对复杂的结果集。后面详细讲!
-->
<select id="queryUserById" resultMap="userResultMap">
select * from tb_user where id=${id}
</select>
由于默认情况下自动映射autoMapping设置为true,所以只需要指定ID,其他的字段只要数据库字段名和POJO名相同就可以自动映射(或者开启驼峰标识时,符合驼峰标识的规范也可以)。
8.SQL片段和动态SQL
SQL片段:
动态SQL:
动态SQL实例:
9.CDATA避免字符转义
二、Spring
为什么使用Spring ?
1.方便解耦,简化开发
通过Spring提供的IoC容器,可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。
2.AOP编程的支持
通过Spring提供的AOP功能,方便进行面向切面的编程,如性能监测、事务管理、日志记录等。
3.声明式事务的支持
4.方便集成各种优秀框架
5.降低Java EE API的使用难度
如对JDBC,JavaMail,远程调用等提供了简便封装
1.IOC控制反转和DI依赖注入
IOC:Inverse of control 控制反转 ,就是在项目中引入一个工厂容器,创建项目中接口依赖的对象,实现项目中对于依赖对象解耦合。 将程序中对象的创建权,交给工厂容器来管理。
Spring其实就是一个工厂,出现为了解除程序中耦合,底层原理:工厂、配置文件、反射。
程序不需要自己创建对象,获取spring工厂已经创建好的对象,对象创建权,反转到spring容器。
读取配置文件的工厂对象
ClassPathXmlApplicationContext 读取 src下配置文件
FileSystemXmlApplicationContext 读取 WEB-INF下配置文件
DI :Dependency Injection 依赖注入,本质上就是在IOC容器运行期间,动态的将某种依赖关系注入到对象中。
2.注解方式实现IoC 容器配置
Spring2.5 提供 @Component 效果相当于< bean >元素
2.1注解定义实现类对象
第一步:在Bean class 添加 注解
当注解只有一个value属性要写时,value= 可以省略
相当于 < bean id=“userService” class=“全路径”>
在实现类加原接口的声明:
// 业务实现类
@Component("userService")
public class UserServiceImpl implements UserService {
@Override
public void login() {
System.out.println("业务层 login ...");
}
}
第二步: 配置包扫描,通知spring 注解Bean 在哪个包下面
<?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/context/spring-context.xsd">
<!-- 自动扫描 cn.itcast.spring包和其所有子包 -->
<context:component-scan base-package="cn.itcast.spring" />
</beans>
Spring 容器提供@Component 等效三个衍生注解
@Repository 用于注册DAO(持久层 )
@Service 用于注册 Service(业务层)
@Controller 用于注册 Action (表现层)
3.注解实现属性依赖注入
简单类型属性注入,只有变量才有意义 !
Spring3.0之后,通过@Value注解 结合 spEL 表达式实现
// 基本类型属性
@Value("哈哈哈哈")
private String company;
3.1 注入复杂类型属性
Spring3.0提供@Value注解
// 复杂类型属性
// 第一种 @Value 结合 spEL
@Value("#{userDAO}")
private UserDAO userDAO;
Spring2.0 提供@Autowired 注解 结合 @Qualifier 注解
// 第二种 @Autowired 注解 结合 @Qualifier 注解
// 如果单独使用@Autowired 默认按照类型注入
// 使用 @Qualifier 按照名称注入
@Autowired
@Qualifier("userDAO")
private UserDAO userDAO;
如果单独使用@Autowired 默认按照类型注入
使用 @Qualifier 按照名称注入
3.2 其它注解的使用
3.2.1 初始化和销毁注解
< bean> 通过 init-method 指定初始化方法 和 destroy-method 指定销毁方法
@PostConstruct 初始化方法
@PreDestroy 销毁方法
package cn.itcast.spring.c_other;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component("lifecycleBean")
public class LifeCycleBean {
public LifeCycleBean() {
System.out.println("LifeCycleBean 构造...");
}
@PostConstruct
// 初始化方法
public void init() {
System.out.println("LifeCycleBean 初始化...");
}
@PreDestroy
// 销毁方法
public void destroy() {
System.out.println("LifeCycleBean 销毁...");
}
}
执行销毁方法,必须bean是单例的,而且调用容器close方法!
@Test
public void testLifeCycle() throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"applicationContext.xml");
LifeCycleBean lifeCycleBean1 = (LifeCycleBean) applicationContext
.getBean("lifecycleBean");
LifeCycleBean lifeCycleBean2 = (LifeCycleBean) applicationContext
.getBean("lifecycleBean");
System.out.println(lifeCycleBean1);
System.out.println(lifeCycleBean2);
// 通过反射 代码调用 close方法
Method closeMethod = applicationContext.getClass().getMethod("close");
closeMethod.invoke(applicationContext);
}
3.2.2. Bean的作用域注解
< bean> 提供 scope属性,用于描述Bean的作用域
Spring提供**@Scope**注解,描述Bean的作用域
默认scope作用域 singleton !
@Component("lifecycleBean")
@Scope("prototype")
// 多实例Bean
public class LifeCycleBean {...}
4.AOP编程
应用场景:
- 事务管理
- 记录日志
- 监测性能(统计方法运行时间)
- 权限控制
- 缓存
简介:AOP全称:Aspect-Oriented Programming,面向切面编程。AOP,面向切面编程,就是把可重用的功能提取出来,然后将这些通用功能在合适的时候织入到应用程序中,比如事务管理、权限控制、日志记录、性能统计等。AOP并没有帮助我们解决任何新的问题,它只是提供了一种更好的办法,能够用更少的工作量来解决现有的一些问题,使得系统更加健壮,可维护性更好。
1.AspectJ AOP切面编程(注解)
AspectJ 共提供6种通知类型(前置、后置、环绕、异常、最终通知),AspectJ通知不需要实现任何接口 。
@Before @AfterReturning @Around @AfterThrowing @After
service和dao代码省略
编写切面类:
package cn.itcast.a_aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
// 切面类
@Component("myAspectJ")
// @Aspect 说明这个类是切面类,里面包含增强方法
@Aspect
public class MyAspectJ {
// 前置通知
@Before("bean(*Service)")
public void before01(JoinPoint joinPoint) {
System.out.println("--------------------- 前置通知: 开启事务 ... ..." );
}
// 后置增强
@AfterReturning(value = "bean(*Service)", returning = "returnObject")
public void afterRegurning(JoinPoint joinPoint, Object returnObject) {
System.out.println("--------------------- 后置通知: 提交事务 ... ..." );
}
// 异常通知
@AfterThrowing(value = "bean(*Service)", throwing = "ex")
public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
System.out.println("--------------------- 异常通知: 回滚事务 ... ..." );
}
// 最终通知
@After("bean(*Service)")
public void after(JoinPoint joinPoint) {
System.out.println("--------------------- 最终通知: 释放资源 ... ..." );
}
//环绕通知
@Around ("bean(*Service)")
...
}
切面类用@Component注解声明,并用@Aspect注解来标识切面类
@Before(“bean(*Service)”) 为切入点表达式
使用注解要开启注解自动代理:
<!--开启注解自动代理-->
<aop:aspectj-autoproxy proxy-target-class="false"/>
@Pointcut 注解使用
切点方法定义规则: 私有无返回值无参数方法 ,添加@Pointcut注解,方法名就是切点名称
package cn.itcast.a_aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
// 切面类
@Component("myAspectJ")
@Aspect
// @Aspect 说明这个类是切面类,里面包含增强方法
public class MyAspectJ {
@Pointcut("bean(*Service)")
private void myPointCut() {
}
// 前置通知
@Before("myPointCut()")
public void before01(JoinPoint joinPoint) {
System.out.println("--------------------- 前置通知: 开启事务 ... ..." );
}
...
}
AOP套路:编写目标类,编写增强类,建立关系。
Spring引用外部配置文件
<context:property-placeholder location="classpath:jdbc.properties"/>
5.Spring事务管理
5.1事务的三个高级接口
PlatformTransactionManager 平台相关事务管理器
TransactionDefinition 事务定义信息 (管理事务的配置信息 )
TransactionStatus 事务运行状态
1.PlatformTransactionManager 平台事务管理器
TransactionManager是整个spring事务管理核心对象,提供管理事务相关方法
2.TransactionDefinition事务定义信息
TransactionDefinition 主要指 spring管理事务过程中,配置如何对事务进行管理
(隔离级别、传播行为、超时时间、 是否只读)
getName 获取事务名称
getIsolationLevel 获取事务隔离级别
什么是传播行为?
和隔离级别不同,不是数据库提供问题解决方案,而是spring针对实际开发中具体事务问题,引入事务解决方案,解决两个事务互相调用的问题 !
REQUIRED、SUPPORTS、MANDATORY:支持当前事务 (删除用户、删除订单)
REQUIRES_NEW、NOT_SUPPORTED、NEVER:不支持当前事务 (ATM取钱、打印凭条)
NESTED 嵌套事务,只对DataSourceTransactionManager 有效,底层原理SavePoint 保存点
3.TransactionStatus 事务状态信息
指事务运行过程中,某个时间点事务状态信息
事务管理总体流程:
用户想使用spring进行事务管理 ,对事务管理进行配置(TransactionDefinition),选用针对持久层技术事务管理器 TransactionManager, TransactionManager根据TransactionDefinition 进行事务管理,在事务管理过程中通过 TransactionStatus获取当时事务状态
5.2使用tx、aop配置进行声明式事务管理
一般使用配置文件的方式使用事务,统一管理,集中配置。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource03"/>
</bean>
<!--配置事务Advice和管理属性-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 配置事务管理属性,TransactionDefinition -->
<!--
name 方法名
isolation 隔离级别 默认DEFAULT
propagation 传播行为 默认 REQUIRED
timeout 超时时间 默认 -1 不超时
read-only 是否只读 默认false 不是只读
rollback-for 配置一些异常,发生这些异常事务进行回滚
no-rollback-for 配置一些异常,发生这些异常,将被忽略,事务仍然进行提交
-->
<tx:method name="transfer"/>
</tx:attributes>
</tx:advice>
<!--配置切入点和切面-->
<aop:config proxy-target-class="false">
<aop:advisor advice-ref="txAdvice" pointcut="bean(*Service)"/>
</aop:config>
6.Spring与mybatis的整合
整合的思路
- SqlSessionFactory对象应该放到spring容器中作为单例存在。
- 传统dao的开发方式中,应该从spring容器中获得sqlsession对象。
- Mapper代理形式中,应该从spring容器中直接获得mapper的代理对象。
- 数据库的连接以及数据库连接池事务管理都交给spring容器来完成。
三、SpringMVC
MVC是一种架构模型,本身没有什么功能,只是让我们的项目结构更加合理,流程控制更加清晰,一般包含三个组件:
Model(模型):数据模型,用于提供要展示的数据。一般包含数据和行为(也就是业务),在JavaWEB中,数据和业务往往是分离开的。
View(视图):负责对模型数据进行展示,例如我们看到的网页。概念比较广泛,可以是:html、JSP、excel、Word、PDF、json、XML等
Controller(控制器):接收用户请求,委托给模型做处理,处理完毕返回数据,再交给视图做渲染,相当于调度员工作
1.SpringMVC执行流程
2.SpringMVC配置文件
在配置文件中需要配置:HandlerMapping处理器映射器、HandlerAdapter处理器适配器、Handler处理器、viewResolver视图解析器
这个文件默认是去寻找:WEB-INF/{web.xml中定义的servletName}-servlet.xml
SpringMVC的jar包中默认已经定义了2个HandlerMapping和3个HandlerAdapter,系统会自动加载这些类。因此,一般我们只需要配置 Handler和视图解析器就够了
传统的方法Handler(具体的处理器)在SpringMVC中,一般是叫做Controller(控制器),我们可以自定义类,实现Controller接口,就称为控制器了。但是有很多缺点:
1) 类必须实现Controller接口,不友好。
2) 每个类中只能有一个默认处理方法,只能处理一个用户请求。
3) 每个类需要在配置文件中进行配置,很麻烦。
所以主要使用注解的方式实现!
注解的配置文件
1) 开启注解驱动
2) 开启扫描包
3) 配置内部资源解析器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启注解驱动,就不要配置HandlerMapping和HandlerAdapter了 -->
<mvc:annotation-driven />
<!-- 不再配置Controller的Bean了,直接配置包扫描 -->
<context:component-scan base-package="cn.controller" />
<!-- 视图解析器,这里是用内部资源视图解析器,其实就是指向项目中的jsp文件.路径是:prefix + 视图名称 + suffix
Example: prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> "/WEB-INF/jsp/test.jsp" -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
3.RequestMapping请求映射方式
规则:
1) @RequestMapping可以设置在类上,也可以设置在方法上
2) 请求的映射规则是:类上的RequestMapping + 方法上的RequestMapping
3) 如果没有写 / ,SpringMVC会自动补全
4) 类上的RequestMapping可以省略,这时直接用方法的RequestMapping访问
5) 路径不可重复
Ant风格映射
占位符映射
@RequestMapping(value="/users/{userId}") :
其中{xxx}占位符, 请求的 URL 可以是 “/users/123456”或“/users/abcd”,
通过@PathVariable 可以提取 URI 模板模式中的{xxx}中的xxx变量。
请求方式限定method
可以通过@RequestMapping注解中的 method属性来限定客户端的请求方式,method属性可以接收的是一个枚举数组
请求参数限定params
我们还可以通过@RequestMapping注解的params属性来对请求的参数进行限定
4.视图解析(与前端页面的交互)
后台返回数据的几种情况
1.返回JSON
在方法上加 @ResponseBody 注解,是把返回值的Pojo对象变为JSON字符串,称为序列化
原理:
1) 当SpringMVC读取到方法上的@ResponseBody注解时,就知道该方法不再使用默认的视图解析器解析视图,
而是直接把结果写到响应体中,这样就需要对结果进行转换。
2) SpringMVC会从框架中查找有没有定义MessageConvertor(消息转换器),通过消息转换器转换结果,返回对应视图
3) 在SpringMVC的注解驱动类中,会进行默认的消息转换器注册,因为引入了jacksonJson包,
所以会注册JSON的消息转换器
如果有多个消息转换的依赖被引入,会根据请求头中的accept来判断返回什么类型数据
2.返回视图名称(String)
SpringMVC允许直接返回一个String数据,作为视图名称。不需要数据模型。
3.重定向和转发
返回ModelAndView,或者没有写redirect和forward时,默认都属于转发。
重定向:redirect:/hello.do 重定向到hello.do
两次请求,浏览器地址会变化
转发:forward:/hello.do 转发到hello.do
一次请求,地址不变
4.返回成功状态
方法上加 @ResponseStatus(HttpStatus.OK)
接受页面传来的数据几种情况
1.获取PathVariable参数
参数列表中,在接受的变量前加注解:@PathVariable(“name”)
参数类型必须匹配,否则会出错
2.接受基本参数类型@RequestParam()
在参数列表的变量前加 @RequestParam() 注解,括号中的值和页面上表单的name属性相同,如果有多个相同的name可以用数组或者list接受。
@RequestParam()的更多用法
3.接受自定义pojo
单个对象情况下,页面中name和对象中的属性名相对应,直接在参数列表写该对象就可以接受到。
多个对象情况下,不能直接接受对象的list,这样会报错,应该再创建一个新的对象B,里面定义接受对象A的list集合,最后在参数列表写对象B。
4.接收JSON格式请求
在参数前面加 @RequestBody 是把接收到的JSON字符串变为Pojo对象,称为反序列化
5.拦截器
preHandle:预处理回调方法,在Handler执行前执行,第三个参数为处理器(Controller 实现);
返回值:
true 表示继续流程(如调用下一个拦截器或处理器);
false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器;
postHandle :后处理回调方法,实现处理器的后处理(但在渲染视图之前)
afterCompletion: :整个请求处理完毕回调方法,即在视图渲染完毕时回调
执行顺序分别为正反反! 也就是说,当拦截器3的预处理报错时,会执行已经执行预处理过的after方法,也就是直接跳到拦截器2 的after方法执行。