前端控制器必须有。核心红色
映射器 适配器注释了也可以运行(框架可以自己找)
如果需求多了 需要使用了必须配置
映射器和适配器的替代品
mvc:annotation-driven标签(不能同时存在)
后端控制器自定义的类。绿色需要自定义实现,可以有很多
视图解析器,配置会产生变化
渲染不用配置
适配器模式
springmvc 框架中涉及的模式
适配器模式:接口、抽象类、实现类
springmvc 流程中涉及的 springmvc组件(组成元件、组成元素)
1)前端控制器
前端控制器是执行流程的中心,也是执行流程的出入口,前端的控制中心,配置一次、加载 springmvc 配置文件,不处理请求。
2)映射器
可以不配置、框架底层到 properties 文件中自动加载,也可以使用注解驱动代替配置,查找映射关系(哪个后端控制器处理哪个请求)
3)适配器
可以不配置,框架底层到 properties 文件中自动加载,也可以使用注解驱动代替位置,起到适配的作用,可以调用不同的后端控制器(例如tpec口可以连接不同设备)
4)后端控制器
需要自定义,可以有很多,其中的方法是处理某个请求的具体位置,后端控制器可以和业务层交互,可以封装模型和视图名
5)视图解析器
可以不配置,框架到 properties 文件自动加载,也可以配置(其他配置需求),通过视图名查找视图文件(文件被封装到视图对象中 View 类型的对象)
6)mvc 注解驱动
代替上面的映射器和适配器,也可以提供其他相关配置
类中方法可以设置的返回值类型有哪些?
1)ModelAndView
A、特点:使用 ModelAndView 作为方法返回值的类型,可以使用 ModelAndView 类型的对象设置模型数据和视图名;被设置到 ModelAndView 中的模型数据最后会转入 request 域对象;响应方式为转发方式;会经过流程中的视图解析器。
2)void
A、特点:使用void作为方法的返回值类型,那么通过原生的 request 和 session 设置数据;响应方式可以转发、重定向;不在经过视图解析器
sendRedirect 重定向不能访问WEB-INF 路径,重定向 / 代表项目根目录。
3)String
A、默认
可以通过 Model(接口)、ModelMap(实现类)、Map 设置模型数据;数据同样转入 request;视图名就是返回值;是转发响应方式;经过视图解析器
B、关键字设置:forward(转发) redirect(重定向)【冒号分割】
与原生redirect不同,带了项目名
RedirectAttributes 重定向参数(底层还是 session 传递 参数),
addFlashAttribute("name",xxx)可以重定向传递参,结合**@ModelAttribute**("name")注解用形参String xxx获取,
可以通过 Model(接口)、ModelMap(实现类)、Map 设置模型数据;数据同样转入 request;关键字添加在返回值里面,返回值是视图名或者是URL;不经过视图解析器
@ModelAttribute 从域对象获取值
@ResponseBody 声明是异步请求和响应,框架底层会借助jackson实现对象转json串,前端jQuery中底层也有操作:json串转回对象
jackson-databind 2.9.10版本
高版本 springboot 需求
4)实体类、集合等相关类型 -- 通常结合异步操作
A、特点:和异步结合、传递过程中使用 json 串(表单、超链接传递、ajax接收)(从后端控制器向也面传数据和从页面向后端传数据)
(原生异步请求JS对象XHR createXHR open、send、get
responseText
XMLHttpRequest)
1. open(method, url, async) 方法需要三个参数:
method:发送请求所使用的方法(GET或POST);与POST相比,GET更简单也更快,并且在大部分情况下都能用;然而,在以下情况中,请使用POST请求:
无法使用缓存文件(更新服务器上的文件或数据库)
向服务器发送大量数据(POST 没有数据量限制)
发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠
url:规定服务器端脚本的 URL(该文件可以是任何类型的文件,比如 .txt 和 .xml,或者服务器脚本文件,比如 .asp 和 .php (在传回响应之前,能够在服务器上执行任务));
async:规定应当对请求进行异步(true)或同步(false)处理;true是在等待服务器响应时执行其他脚本,当响应就绪后对响应进行处理;false是等待服务器响应再执行。
2. send() 方法可将请求送往服务器。
3. onreadystatechange:存有处理服务器响应的函数,每当 readyState 改变时,onreadystatechange 函数就会被执行。
4. readyState:存有服务器响应的状态信息。
0: 请求未初始化(代理被创建,但尚未调用 open() 方法)
1: 服务器连接已建立(open方法已经被调用)
2: 请求已接收(send方法已经被调用,并且头部和状态已经可获得)
3: 请求处理中(下载中,responseText 属性已经包含部分数据)
4: 请求已完成,且响应已就绪(下载操作已完成)
5. responseText:获得字符串形式的响应数据。
6. setRequestHeader():POST传数据时,用来添加 HTTP 头,然后send(data),注意data格式;GET发送信息时直接加参数到url上就可以,比如url?a=a1&b=b1。
PS:Fetch polyfill 的基本原理是探测是否存在window.fetch方法,如果没有则用 XHR 实现。
5)四种返回值类型的对比
A、数据的处理:ModelAndView 直接封装数据;void 是使用原生 request 或者 session 封装数据;String 是 Model、ModelMap、Map 封装数据;实体类或者集合类型是直接返回数据
B、视图处理:ModelAndView 直接封装视图名;void是使用 request 或者 response 封装视图;String 返回值就是视图名;实体类或者集合不需要设置页面
传参 -- 参数传递、参数绑定(从也面向后端控制器传递数据)
1)主要介绍在页面把数据送到后端控制器之后,后端控制器如何接收数据
2)方式:原生 request 方式、
同名形参的方式
(框架借助 ioc、di req.getParameterNames实现)、不同名形参方式、
@RequestParam 实现名称匹配
属性 | 属性释义 |
---|---|
value | 请求参数名称(映射到参数) |
required | 是否必须包含参数,默认true |
defaultValue | 没有提供参数,使用指定的默认值 |
使用实体类封装、使用数据封装、使用集合封装
RequestMapping 默认可以缺省.do配置(会自动补齐)
实体类
1)实现
同名形参,表单名和实体类字段名一致
2)中文乱码处理方式
超链接 get 请求方式中文没问题(Tomcat 版本问题)
表单 post 请求方式 中文乱码
过滤器配置,框架提供好
<!-- 配置全局过滤Filter-->
<filter>
<filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name>
<!-- 所有请求都被过滤-->
<url-pattern>/*</url-pattern>
</filter-mapping>
3)在参数传递过程中,可能发生日期类型转换问题,如何解决?
局部和全局方式
A、局部方式是框架提供的
@DateTimeFormat(pattern="yyyy-MM-dd") 将指定格式转成日期格式,要求送来的格式正确。(缺点每个地方都要加入)
(400 状态码 代表坏请求 请求参数有问题,在此是类型转换问题)
B、全局方式是自定义的
先自定义一个日期转换的类 实现接口 Converter
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String dateStr) {
// 将日期字符串转换成日期对象 返回
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = format.parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
转换器工厂:可以包含多种,自定义、框架提供
<bean id="conversionService" class="org.springframework.context.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.bh.converter.DateConverter"></bean>
</set>
</property>
</bean>
工厂注册:
<mvc:annotation-driven conversion-service="conversionService"/>
数组
同数组名即可(底层request.getParameterValues)
集合 -- list、set、map
集合需要绑定在对象上,而不能直接写在Controller方法的参数中。
1)List 集合接收数据
taglib
c 核心标签
c:forEach 做便利输出
items 结合 EL 表达式
var
varStatus 下标 借助EL表达式 .index 获取下标
fmt 格式化标签
fmt:formatDate
value pattern,做日期格式化
单双引号嵌套 防止错误
PojoVO 设置 集合对象pojo 封装属性List<>,专门接收对象(前端加索引下标确定对象,动态下标)
2)set 集合接收数据
局限性 VO类 必须 newHashSet,并且构造方法add对象。
3)map集合接收数据
map[key名].对象属性
异步
1)从页面向后台传递的数据以 json 串方式传递
// 自定义json串
var jsonData = "[{'uid':1003,'uname':'张飞','upwd':'123'},{......}]";
// 异步请求
$.ajax({
url:"",
type:"post",
data:jsonData,
dataType:"json",
contentType:"application/json;charset=UTF-8",
cache:false,
success:function (obj) {
console.log(obj);
}
});
@RequestBody 把 json 串转成对象 底层还是jackson
异步加@ResponseBody
// json串转对象
public void xx(@RequestBody 对象) {
xxxdo
}
REST 风格 (英文:Representational State Transfer)是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。它是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。
直译:表现层状态转换
是指资源发生状态转换,在表现层发生;即资源在表现层发生状态转换。
http 协议 无状态协议(不知道从前、当前、未来的状态)
1)网络上:URL对应资源,需要请求什么资源就对应URL,在资源请求过程中,会发生 由当前所处的状态转换成另一种状态,资源需要知道自己下一个要转换的状态是哪种状态,但是 URL 中 http 协议不带有状态信息,直接使用 http 协议不能告知资源要转换成哪种状态,解决?
http 协议含有不同的请求方式,所以利用不同的请求方式来告知资源下一个要转换状态是什么
2)请求方式和对应状态
有不同的请求方式(8个?)
Get 请求方式 查询状态 对应(资源变成查询状态、实际上就是实现资源的查询)
Post 请求方式 增加状态 对应(资源变成增加状态,实际上对应就是资源的增加)
Delete 请求方式 删除状态 对应(资源变成删除状态,实际上对应就是资源的删除)
Put 请求方式 修改状态 对应(资源变成修改状态,实际上对应就是资源实现了修改)
3)简而言之:如果采用 restful 风格来实现项目,那么设计 URL 的同时还要设计对应的请求方式
使用"url+请求方式"表示一次请求目的
restful 风格的 URL 样式
1)传统 URL 和参数的格式
http://localhost:8080/项目名/资源名.do
http://localhost:8080/项目名/资源名?key1=value&k2=value2
2)restful 风格的 URL 和参数的格式
入门案例 -- springmvc 支持 result 风格
*需要DispatcherServlet 路径由 .do 改为 /
/ 代表匹配所有(除了jsp页面请求)不能直接进入jsp页面
1)使用 @GetMapping 只处理Get请求,表示资源要转为查询状态,资源查找
405 请求不支持
2)使用 @PostMapping 只处理Post请求
@PathVariable("xx") 从URL中通过指定变量名找到值,并注入给形参
@GetMapping("xxx/{id}/{name}")
public String xxx(@PathVariable("id") int uid,@PathVariable("name") int uname,) {
}
3)post 请求 数据和 URL 分离 不用串入 URL
put、delete http 没有真正意义上实现
是spring模拟的 格式如下
<!-- 固定格式-->
<!-- 由post模拟put请求,put请求是被模拟-->
<form action="xxx" method="post">
<!-- 隐藏文本框-->
<input type="hidden" name="_method" value="PUT">
</form>
@PutMapping 只处理Put请求
加入过滤器在前端控制器上(HiddenHttpMethodFilter)
<filter>
<filter-name></filter-name>
<filter-class>xxx.HiddenHttpMethodFilter</filter-class>
</filter>
4)@DeleteMapping 只处理Delete请求
Tomcat maven插件方式没问题 Tomcat 原生方式会出错(jsp页面只能被get、post请求访问、put、delete不能请求jsp页面)
类上加 RequestMapping 抽取方法相同的映射地址,框架自动将类片段和方法片段拼接匹配
5)*DispatcherServlet 路径由 .do 改为 / 产生的问题
静态资源也被后端控制器处理,倒置无法被读取
正常情况不需要 Controller 去响应
两种解决方式:
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
<mvc:default-servlet-handler></mvc:default-servlet-handler>
@Controller:IOC 实现
@RequestMapping:实现 url 请求和方法匹配
@GoMapping:实现请求的方法和匹配,只处理 get 请求方式
@PostMapping:实现请求的方法和匹配,只处理 post 请求方式
@DeleteMapping:实现请求的方法和匹配,只处理 delete 请求方式
@PutMapping:实现请求的方法和匹配,只处理 put 请求方式
@ResponseBody:声明是异步请求,对象转 json 串,返回
@ModelAttribute:从域对象获取数据;可以把方法的返回值数据暴露给视图(注解在方法上,方法返回值会返回到所有的页面,数据统一管理思想)
@RequestParam:传参时不同名实现匹配;默认值,是否必须传参
@RequestBody:从页面向后台串 json 串时,将 json 串转对象
@DatetimeFormat:实现局部的字符串类型转日期类型
@PathVariable:实现 restful 风格中从 url 里面获取数据,注入给指定形参
@CookieValue:从 cookie 中获取数据
@SessionAttributes:将数据转存到 session,在类上加注解,键值对(value="xxx键值对名")或者实体类型
(EL表达式${sessionScope.xxx}只从session拿数据)
@CookieValue
1)从 cookie 中通过指定的 key 获取数据
2)cookie 会话跟踪 (请求时候电脑信息送到对方)sessionId 借用 cookie 送回服务器端
3)使用
@RequestHeader
1)获取请求头中的信息
上传 -- 从用户端把文件上传到服务器端
1)注意事项
A、前端页面:必须是 post 请求;表单中添加input[type=file];form[encType=multipart/form-data] 默认键值对格式、改成字符串格式(同步上传方式),异步需要form-data
B、上传解析器 -- 把用户端向服务器端发送的内容,进行字符串截取,截取之后注入到对应的位置。
C、考虑重名位置、考虑上传文件保存位置问题
2)实现
A、创建项目,导入依赖
(commons-io 会传递依赖)
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
B、springmvc 配置文件中添加上传解析器
(id 名称是固定的)
<!-- 配置文件上传解析器 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver
">
<!-- 编码 -->
<property name="defaultEncoding" value="utf-8"/>
<!-- 上传文件总大小限制 的单位B -->
<property name="maxUploadSize" value="5242800"/>
</bean>
String 只保存文件名称,不能同名;要保存文件使用字节数组。
C、前端(表单)
D、后端(controller)
文件存储:本机(任意路径)、远程存储(自搭建、别人搭建)
fastDFS(linux 分布式文件系统)
阿里云(对象云存储OOS)
文件解析器先存在c盘临时位置,在使用 transferTo 复制,存储位置
下载
1)从服务器端向用户端下载文件
2)实现
A、准备下载列表
B、点击链接,下载对应文件
C、后端实现下载功能
new File().list 文件名称列表展示
下载 原生方案就可以:一个头、两个流:响应头、本地读取流、远程写出流
response.setHeader("content-disposition","attachment;filename="+name)
对字符二次编码 处理中文乱码
name.getBytes("utf-8")
new String(bytes,"iso8859-1")
编译时异常 加 thorw、try catch
运行时错误
代码、前端(正则表达式约束)
不可控异常 运行逻辑异常
异常默认处理方式:向上抛出
抛给异常处理中心
是指:在项目中没有进行异常处理的其他处理,采用 java 默认 异常处理方式, 即向上抛出的方式,你如由持久层抛给业务层,由业务层抛给控制层,控制层抛给异常处理中心;在异常处理中心进行异常的统一处理。
实现:
1)关注异常处理中心的实现
A、自定义异常处理的类 -- 进而创建对象 -- 由容器管理即可
实现 HandlerExceptionResolver
实现的方法 resolveException 即为异常处理中心
返回值 ModelAndView
实现给运维保留信息:采用 Tomcat 自带的日志记录方式(log);向数据库中保存;自定义日志;日志服务器等等;
Exception e 就是抛出的异常对象
e.printStackTrace() 可以使用流
e.getMessage() 获取异常信息
介绍
1)对于静态资源不拦截的;对于向 controller 的请求都会先拦截(然后可以在程序中在进一步判断)
和过滤器对比
1)过滤器 依赖于 web 容器(servlet 容器 Tomcat造)(类加载造、方法调用造 load-on-startup)
// 非静态方法 servlet 对象 调用
UserServlet{
Init();
Destroy();
Service();
}
拦截器 依赖于 springmvc 容器
2)过滤器采用函数回调方式实现过滤器功能;拦截器采用反射方式实现拦截功能,基于 AOP 思想进行切入
3)拦截过滤的顺序:请求时先过过滤器再过拦截器;响应时先过拦截器再过过滤器(先进后出)
4)过滤器可以过滤所有请求,拦截器只可以拦截 controller 的请求
实现
实现 HandlerInterceptor
实现三个方法
preHandler:请求处理之前调用
postHandle:返回模型和视图名之前切入,可以获取到后端控制器向适配器返回的模型和视图名,通常在此方法中可以实现模型和视图名的统一设置
afterCompletion:也没有拦截或者放行的功能,此方法的切入位置是在视图解析器向前端控制器返回视图文件时,可以获取到向 controller 发出请求时发生的异常。统一异常处理另一套方案,无法设置返回页面。
(不使用异常处理中心的方案时)
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 对那些资源执行拦截操作 /**代表对所有方法 -->
<mvc:mapping path="/**"/>
<bean class="com.bh.interceptor.Myinterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
/** 表示一级多级都可以拦截
需求:登录拦截
有些请求不需要登录就可以直接访问;但是还有些请求是需要登录才可以访问的;当用户请求需要登录才可以访问的连接,使用拦截器拦截,进行登录验证(验证用户是否登录),登录则放行,反之则登录
拦截器获取当前请求 url
request.getRequestURI()
if endsWith() 判断后缀是什么
1)需要登录才可以访问的
判断是否有登陆...
2)不需要登录就可以访问的
注意:url 片段前面是否有/,如果没有,则默认当前 url 统计目录下;如果有/,则代表当前根目录,端口后,不带项目名称
整合
SSM -- SpringMVC、Spring、MyBatis
协作:共同实现项目功能、完成项目的需求;
SpringMVC 负责表现层的实现
Spring 负责 IOC、DI、AOP 实现
MyBatis 负责持久层的实现
步骤:
创建项目、导入依赖
SpringMVC 整合 Spring
1)web.xml 中配置前端控制器、过滤器
2)SpringMVC 配置文件(扫描包、注解驱动、视图解析器、类型转换工厂、上传解析器)
3)测试
Spring 和 MyBatis 整合
1)Spring 配置
扫描包、数据源、事务管理对象、事务注解驱动、MyBatis工厂、代理对象
2)准备 MyBatis 映射文件
增删改查、动态SQL 相关配置
3)测试
把整合结果整合到项目中
加载 Spring 配置文件
等同于
ApplicationContext context = new XmlClasspathApplicationContext("applicationContext.xml");
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Spring 容器和 SpringMVC 容器,父子容器,Spring 是父,SpringMVC 是子;SpringMVC 可以调用父容器对象,反之不可以。
1)web.xml 添加配置
A、加载文件配置
B、监听器配置
整体测试