SpringMVC
介绍
简介
- 基于 Spring 的框架,基于 MVC 架构
- 轻量级框架,不依赖特定的接口和类
- 实际就是 Spring 的一个模块,专门做 Web 开发
- Servlet 的升级版
- web 开发底层是 servlet
- 框架在 servlet 的基础上添加一些功能,更方便 web 开发
- 作为 Spring 框架的一部分能使用 Spring 的 IoC 管理对象 和 AOP 面向切面
- SpringMVC 创建对象放到 SpringMVC 容器中
- 存放控制器对象
- SpringMVC 创建对象放到 SpringMVC 容器中
- 强化注解使用
- 在
controller
、service
、dao
层都可以使用注解,方便灵活 @Controller
注解创建控制器对象@Service
注解创建业务对象@Autowired
或@Resource
注解- 在 controller 中注入 Service
- 在 Service 类中注入 Dao
- 在
SpringMVC
SpringMVC 执行分析
启动
-
tomcat 启动,创建容器代理对象
- 通过
load_on_start
标签指定的1
创建DispatcherServlet
对象- 指定为
tomcat
服务器启动时即创建对象
- 指定为
DispatcherServlet
继承自HttpServlet
- 被创建时会执行
inint()
方法
- 被创建时会执行
- 通过
-
init()
方法中读取配置文件创建容器代理对象-
ApplicationContext context = new ClassPathXMLApplicationContext("springmvc-config.xml");
-
将容器对象放到
servletContext
中getServletContext().setAttribute(key, context);
-
-
创建容器的作用
- 扫描 SprngMVC 的配置文件,创建 @Controller 注解类对象
- 自定义的控制器 myController 对象
- 将控制器对象放到 springMVC 容器
- 类似 map:put(“myController”, MyController 对象)
- 扫描 SprngMVC 的配置文件,创建 @Controller 注解类对象
请求流程
-
发起请求:例如
some.do
-
请求到
tomcat
服务器- 读取
web.xml
配置文件 - 根据
url-pattern
找到处理.do
请求的中央调度器DispatcherServlet
- 读取
-
DispatcherServlet
读取配置文件spring-config.xml
- 通过组件扫描器找到控制器对象
MyController
- 以及
some.do
请求处理方法doSome
- 以及
- 将请求转发给
MyController
的doSome
方法进行处理
- 通过组件扫描器找到控制器对象
-
框架执行
doSome
方法-
将得到的
ModelAndView
对象进行处理 -
并转发到结果显示页面
show.jsp
some.do → DispatcherServlet → MyController → doSome() → show.jsp
-
请求处理
- 执行
Servlet
的service
方法 service
方法调用doService
方法doService
方法会调用中央调度器方法- 即
doDispatch(request, response)
方法
- 即
doDispatch
方法执行自定义控制类的处理方法(doSome)
简单示例
- 需求:用户在页面发起请求,请求交给 SpringMVC 控制器对象,显示请求的处理结果
- 简单实现步骤
- 创建 maven 工程
- 添加项目依赖
- spring-mvc依赖,会间接加入 spring 依赖到项目中
- jsp、servlet 等相关依赖
- 在
web.xml
文件注册SpringMVC
框架核心对象:DispatcherServlet
DispatcherServlet
:中央调度器,是一个 servlet,父类继承HttpServlet
- 也叫做前端控制器:
front controller
- 负责接收用户请求,调用控制器对象,并将请求的处理结果显示给用户
- 也叫做前端控制器:
- 创建发起请求的页面
index.jsp
- 创建控制器类
- 类声明上注解
@Controller
创建对象,注入 SpringMVC 容器 - 在类中方法上注解
@RequestMapping
接收请求
- 类声明上注解
- 创建作为结果的 jsp 页面显示请求的处理结果
- 创建 SpringMVC 的配置文件
- 类似 Spring 的配置文件
- 声明组件扫描器,指定
@Controller
所在包名 - 声明视图解析器,帮助处理视图
web.xml
作用
- 声明 springMVC 的 servlet 核心对象
- tomcat 启动后创建 DispatcherServlet 对象实例
- 在其创建过程中会创建 SpringMVC 容器对象
- 读取 SpringMVC 配置文件并将其中的对象都创建
- 用户发起请求时可以直接使用对象
- tomcat 启动后创建 DispatcherServlet 对象实例
- servlet 初始化会执行 init() 方法,
DispatcherServlet
就在init()
中- 读取配置文件创建容器对象:
ApplicationContext context = new ClassPathXMLApplicationContext("spring-config.xml");
- 将对象放到
servletContext
中getServletContext().setAttribute(key, context);
- 读取配置文件创建容器对象:
<?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_4_0.xsd"
version="4.0">
<!-- 声明 springMVC 的 servlet 核心对象 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 初始化参数,读取 springmvc 配置文件 -->
<init-param>
<!-- springmvc 配置文件 -->
<param-name>contextConfigLocation</param-name>
<!-- 配置文件的位置 -->
<param-value>classpath:springmvc-config.xml</param-value>
</init-param>
<!-- tomcat 启动后创建 servlet 对象 -->
<!-- 标签值是整数,表示创建对象的顺序,值越小越先创建 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 请求结果映射 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- 将获取的以 .do 结尾的请求都交给 springmvc 处理 -->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<filter>
<!-- 配置字符编码过滤器,解决 post 请求中文乱码 -->
<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>
<!-- 强制 request 请求使用字符集 encoding -->
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<!-- 强制 response 响应使用字符集 encoding -->
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<!-- 过滤器映射 -->
<filter-mapping>
<!-- 使用字符集过滤器,指定过滤器映射关系 -->
<filter-name>characterEncodingFilter</filter-name>
<!-- /*:表示强制所有请求先通过该过滤器 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
资源请求处理
-
.do
等请求由DispatcherServlet
处理(SpringMVC 框架)- 其他静态资源请求由
tomcat
处理,jsp 也由 tomcat 处理
- 其他静态资源请求由
-
tomcat 本身可以处理静态资源访问
- html、图片、js 文件等都是静态资源
-
tomcat 有默认的 servlet:
DefaultServlet
-
设置为
<Load-on-startup>1</Load-on-startup
- tomcat 启动之后直接创建
-
所有 web 程序的默认 servlet,用于提供静态资源支持
-
处理所有未映射到具有 servlet 映射的其他 servlet 的请求
- 可以自定义参数
-
指定的映射关系:处理
/
请求
<!-- tomcat 配置文件参数 --> <servlet-mapping> <servlet-name>default</servlet-name> <!-- /:表示静态资源和未映射请求由 default 处理 --> <url-pattern>/</url-pattern> </servlet-mapping>
-
-
tomcat 中还有另一个 servlet:JspServlet
-
设置为
<load-on-startup>3</load-on-startup>
映射关系:处理
*.jsp *.jspx
请求<servlet-mapping> <servlet-name>jsp</servlet-name> <url-pattern>*.jsp</url-pattern> <url-pattern>*.jspx</url-pattern> </servlet-mapping>
-
url-pattern
使用
-
声明 servlet 对象
DispatcherServlet
后建立映射关系处理对应请求- 设置
<servlet-mapping>
标签 - 通过
url-pattern
指定处理请求的类型
- 设置
-
使用框架时标签的
url-pattern
可使用两种值<servlet-mapping> <servlet-name>springmvc</servlet-name> <!-- 获取的以 .do 结尾的请求都交给 springmvc 处理 --> <url-pattern>*.do</url-pattern> <!-- 或使用 / 表示获取所有请求 --> <url-pattern>/</url-pattern> </servlet-mapping>
- 扩展名:语法
*.xxx
xxx
是自定义扩展名;常用.do .action .mvc
等;例如- http://localhost:8080/springmvc/some.do
- http://localhost:8080/springmvc/other.do
- 由 tomcat 服务器默认进行静态资源访问处理
- 动态资源请求由
DispatcherServlet
完成
- 动态资源请求由
- 使用
/
- 自定义 servlet 替代 Tomcat 中的
DufaultServlet
- 无法访问静态资源
- 动态资源(some.do)可以访问
- 程序中有控制器对象可以处理动态资源
- 替代
defautl
之后会导致所有静态资源由DispatcherServlet
处理- 默认
DispatcherServlet
没有处理静态资源的能力- 没有控制器对象可以处理静态资源访问
- 所以静态资源会报 404 异常
- html、js、图片、css 等静态资源
- 默认
- 自定义 servlet 替代 Tomcat 中的
- 扩展名:语法
静态资源访问
<mvc:resources/>
-
使用
<mvc:resources/>
:不依赖 tomcat 服务器处理- 添加
<mvc:resources/>
标签用于解决静态资源访问问题
- 添加
-
容器创建
ResourcesHttpRequestHandler
对象处理静态资源访问,不依赖 tomcat 服务器- Spring3.0 版本后 Spring 专门定义的用于处理静态资源访问请求处理的处理器
-
在 SpringMVC 配置文件中进行配置
-
<mvc:resources location="" mapping=""/>
- location:静态资源所在目录
- 不能在
/WEB-INF/
及其子目录
- 不能在
- mapping:访问静态资源的 url
- 使用通配符
**
表示所有目录下所有资源文件
- 使用通配符
- location:静态资源所在目录
-
<mvc:location location="/static/" mapping="/static/**"/>
- 将所有资源文件目录都放到 static 目录下
- 可以同时指定所有资源文件
**
可以表示当前目录和子目录资源
- 将所有资源文件目录都放到 static 目录下
-
-
会和
@RequestMaping
注解有冲突- 无法访问请求动态资源
- 添加注解驱动可以解决冲突
<!-- 配置注解驱动器,防止 resources 标签和 @RequestMapping 注解冲突 -->
<mvc:annotation-driven/>
<!--
/images/:表示根目录的 images 目录
/images/** :表示 images 目录下所有资源,直接资源和子目录资源
不同资源使用单独标签定义
-->
<mvc:resources location="/images/" mapping="/images/**"/>
<!-- 将所有静态资源都放到 static 目录下,指定一个标签处理所有静态资源 -->
<mvc:location location="/static/" mapping="/static/**"/>
<mvc:default-servlet-handler/>
使用 <mvc:default-servlet-handler/>
:依赖 tomcat 服务器处理
- 标签添加在
SpringMVC
配置文件- 添加后框架自动创建控制器对象
DefautlServletHttpRequestHandler
- 类似自定义的 Controller 对象
- 添加后框架自动创建控制器对象
- 控制器对象处理静态资源访问
- 把接收的请求转发给 tomcat 的 DefaultServlet 处理
- 动态资源请求由自定义处理器进行处理
- 会和
@RequestMapping
注解有冲突- 添加注解驱动以解决冲突
<mvc:annotation-driven/>
- 添加注解驱动以解决冲突
<!-- 配置注解驱动器,防止 handler 标签和 @RequestMapping 注解冲突 -->
<mvc:annotation-driven/>
<!-- 将请求转交给 tomcat 服务器的 DefaultServlet 处理 -->
<mvc:default-servlet-handler/>
页面请求路径
在 jsp、html 中使用的地址都是在前端页面中的地址,都是相对地址
-
<a href="some.do">相对地址</a>
绝对地址
-
带有协议名称
- 例如:http://www.baidu.com
-
可以独立直接使用
相对地址
-
不带协议开头的
- 例如:
user/some.do
- 例如:
-
不能独立使用,必须有参考地址
- 参考地址 + 相对地址才能指定资源
参考地址
相对地址 + 参考地址 表示路径完整地址
访问地址不加/
-
<a href="string.do">跳转链接</a>
- 访问时以当前页面地址+连接地址作为 url
<!-- 当前页面 --> http://localhost:8080/demo13_war/index.jsp <!-- 页面地址 --> http://localhost:8080/demo13_war/ <!-- 资源页面 --> index.jsp <!-- 发起请求 --> string.do <!-- 访问地址发生变化:当前页面地址+访问连接地址作为 url --> http://localhost:8080/demo13_war/string.do`
-
当访问地址不加
/
,而且请求的结果是返回当前页面- 多次点击链接跳转会出现地址错误,两种解决方式
- 使用 el 表达式动态表示路径
- 使用 base 标签指定参考路径
<!-- 当前页面 --> http://localhost:8080/demo13_war/index.jsp <!-- 页面地址 --> http://localhost:8080/demo13_war/ <!-- 资源页面 --> index.jsp <!-- 发起请求 --> sdemo/tring.do <!-- demo/string.do 请求的结果是返回 index.jsp 页面--> <!-- 此时访问页面地址 --> http://localhost:8080/demo13_war/demo/string.do <!-- 地址已发生变化,但仍是在 index.jsp 资源页面 --> <!--再次进行 demo/string.do 请求 --> <!-- 访问地址再次变化 --> http://localhost:8080/demo13_war/demo/demo/string.do <!-- 将当前页面地址继续拼接访问地址,但该地址并不存在,报出异常 --> <!-- 解决方案 1、使用 el 表达式:动态表示项目资源路径地地址,每个地址都要添加 2、使用 base 标签:html 语言标签,表示当前页面中访问地址的基地址 不以 / 开头的地址都会以 base 标签中地址作为参考地址 --> <!-- el表达式 --> <a href="${pageContext.request.contextPath}/demo/string.do">跳转链接</a> <!-- 使用 base 标签指定参考地址 --> <base href="http://localhost:8080/demo13_war/"/> <!-- 实际使用时动态获取项目路径并指定到 base 标签,仅当前页面有效 --> <% String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/"; %> <base href="<%=basePath%>"/>
- 多次点击链接跳转会出现地址错误,两种解决方式
访问地址添加/
<a href="/string.do">跳转链接</a>
- 参考地址为服务器地址
- 访问地址需要写项目资源文件全路径
/demo13_war/demo/string.do
- 访问不灵活
- 需要使用项目中资源文件全路径设置
- 项目资源文件路径更改时会导致无法找到资源文件
- 使用 el 表达式
${pageContext.request.contextPath}
- 动态表示项目资源访问路径
<!-- 当前页面--> http://localhost:8080/demo13_war/index.jsp
<!-- 页面地址 --> http://localhost:8080/demo13_war/
<!-- 资源页面 --> index.jsp
<!-- 发起请求 --> /string.do
<!-- 访问地址改变,但路径并不存在 --> http://localhost:8080/string.do
<!-- 访问请求需要使用项目资源文件全路径 -->
<a href="/demo13_war/demo/string.do">跳转链接</a>
<!-- 使用 el 表达式动态表示项目路径 -->
<a href="${pageContext.request.contextPath}/demo/string.do">跳转链接</a>
<!-- 访问地址动态变化 -->
http://localhost:8080/demo13_war/demo/string.do
springmvc-config.xml
<?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"
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/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 声明组件扫描器,扫描指定包中的注解创建对象 -->
<context:component-scan base-package="demo.controller"/>
<!-- 声明 SpringMVC 框架中的视图解析器,辅助拼接视图文件的路径 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 指定视图文件路径前缀 -->
<property name="prefix" value="/WEB-INF/view/"/>
<!-- 指定视图文件路径后缀 -->
<property name="suffix" value=".jsp"/>
</bean>
<!-- 添加注解驱动,解决标签与注解的冲突 -->
<mvc:annotation-driven/>
<!--
仅在 web.xml 配置文件 servletmapping 标签指定 servlet 映射使用 / 时需要设置
表示静态资源访问方式
-->
<!-- 将所有静态资源放到static目录下,指定处理所有静态资源,不依赖 tomcat 处理 -->
<!-- <mvc:location location="/static/" mapping="/static/**"/> -->
<!-- 将请求转交给 tomcat 服务器的 DefaultServlet 处理 -->
<!-- <mvc:default-servlet-handler/> -->
</beans>
控制器
@Controller
-
@Controller 注解创建控制器对象
-
对象放到 SpringMVC 容器,作为控制器使用
-
控制器对象能接收用户请求、显示处理结果
-
-
注解创建的是普通类对象,不是 servlet
- 但可以当作 servlet 使用
- SpringMVC 框架赋予了控制器对象一些额外功能
- SpringMVC 框架中有 Servlet 对象:
DispatcherServlet
DispatcherServlet
接收用户请求,再将请求转发给控制器对象,控制器对象处理请求
- 但可以当作 servlet 使用
-
index.jsp – 发送请求 → DispatcherServlet - 转发到 → 控制器对象 → 处理请求
@RequestMapping
-
@RequestMapping :请求映射,把一个请求和一个方法绑定在一起
-
属性
value
:String[] 类型,表示请求的url
地址- 值必须唯一,使用时推荐以
/
开头 - 可以添加多个 url 处理多种请求,数组形式以
,
分隔
- 值必须唯一,使用时推荐以
method
:请求方式;get、post 等- 参数为
RequestMethod
枚举类型 - 指定接收请求处理方式为 get:
RequestMethod.GET
- 指定接收请求处理方式为 post:
RequestMethid.POST
- 不指定请求方式时可以接受所有类型请求
- 参数为
-
常用在方法上面,也可用在类上面
- 注解在类上面表示所有方法中
url
的公共路径 - 常简化同一模块下的路径
- 修改模块比较方便
- 注解在类上面表示所有方法中
-
@RequestMapping
修饰的方法叫做处理器方法或访问控制方法- 可以处理请求,类似 servlet 中的 doGet、doPost
- 例如
@RequestMapping("/some.do")
处理 some.do 请求- 在类定义同时存在
@RequestMapping
则实际表示value = "/demo/some.do"
- 在类定义同时存在
方法参数
参数类型
-
控制器(控制器)的方法参数
- 参数在系统调用时自动赋值
- 在方法参数列表直接定义
- 方法内可直接使用
- 参数在系统调用时自动赋值
-
包含四类参数
HttpServletRequest
:请求HttpServletResponse
:应答HttpSession
:会话- 请求中携带的请求参数
- 接收用户提交的参数
逐个接收
-
处理器方法的形参名和请求中的参数名必须一致
- 同名的请求参数赋给同名的形参
- 参数名不一致时无法赋值
-
@RequestParam
注解用于解决请求中参数名和方法形参名不一样的问题value
:请求中参数名required
:默认 true,表示请求中必须有此注解参数- 设为 false 后可以不传参默认赋值
null
- 设为 false 后可以不传参默认赋值
- 注解在方法形参定义前面
-
框架接收请求参数逻辑
-
使用
request
对象接收参数String strName = request.getParameter("name"); String strAge = request.getParameter("age");
-
SpringMVC 框架通过
DispatcherServlet
调用MyController
的方法- 调用方法时按名称对应将接收的参数赋值到形参
doSubmit(strName, strAge)
- 框架可将参数类型自动转换
- 能将 String 解析为 int、long、float、double 等
- 参数类型为 int 只能接受整数,不能为空
- 使用包装类型 Integer 可以接收空值
- 否则报空指针异常
-
输入参数不合法时方法不会执行
- 参数类型错误无法匹配对应的请求处理方法
-
-
post
类型提交请求使用中文会显示乱码- get 请求不会显示乱码
- 使用过滤器处理乱码问题
- 自定义或使用框架过滤器
/**
* 不指定接收请求类型,可处理所有类型请求
* @param name 自定义参数名称
* @RequestParam name1 请求中参数 name1,将其赋值到 name,且不允许为空
* @param age 自定参数名称
* @RequestParam age1 指定请求中参数 age1 赋值到 age,可以传空
* @return 返回请求处理结果
*/
@RequestMapping(value = "/first.do")
public ModelAndView doFirst(@RequestParam("name1") String name,
@RequestParam(value = "age1", required = false) Integer age) {
ModelAndView mv = new ModelAndView();
mv.addObject("姓名", name);
mv.addObject("年龄", age);
mv.setViewName("first");
return mv;
}
过滤器
-
CharacterEncodingFilter
类实现了doFilterInternal
方法- 执行
request.setCharacterEncoding(encoding)
和response.setCharacterEncoding(encoding)
两个方法进行 字符集设置- 这两个属性值被设置为 true 之后才进行字符集设置
- 执行
-
配置并使用过滤器
<filter>
<!-- 配置字符编码过滤器,解决 post 请求中文乱码 -->
<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>
<!-- 强制 request 使用字符集 encoding -->
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<!-- 强制 response 使用字符集 encoding -->
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<!-- 使用过滤器,指定过滤器映射关系 -->
<filter-name>characterEncodingFilter</filter-name>
<!-- /* 强制所有请求先通过过滤器 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
对象接收
- 使用普通 Java 类存放请求中的参数
- 类的属性名和请求中的参数名保持一致
- 在方法中使用对象形参
- 可以同时使用多个对象形参
- 或混搭使用基本类型参数
- 由框架自动创建类的实例对象并完成赋值
- 使用无参构造创建对象
- set 注入属性赋值
- 直接通过对象方法获得参数值
/*
创建普通Java类 Demo,类属性与请求中的形参名一致
创建 set、get 方法进行赋值和属性值调用
*/
/**
* 对象传参
* @param demo 框架自动创建对象并赋值
* @return 返回请求处理结果
*/
@RequestMapping(value = "/submit.do")
public ModelAndView doSubmit(Demo demo){
ModelAndView mv = new ModelAndView();
mv.addObject("myName",demo.getName());
mv.addObject("myAge", demo.getAge());
mv.addObject("demo", demo);
mv.setViewName("submit");
return mv;
}
@RequestBody
-
请求体中的 JSON 字符串绑定到相应的 bean 上
- 也可以将其分别绑定到对应的字符串上
-
login(@requestBody Demo demo){}
- 将请求中的 json 数据绑定到 demo 对象
-
JSON 字符串中的 key 必须对应 user 对象中的属性名
- 否则无法接收参数
// Ajax 请求
$.ajax({
url:"/login",
type:"POST",
data:'{"userName":"admin","pwd","admin123"}',
content-type:"application/json charset=utf-8", // 文本类型为 json 格式
success:function(data){
alert("request success ! ");
}
});
// controller 方法接收 Ajax 请求
@requestMapping("/login")
public void login(@requestBody String userName,
@requestBody String pwd){
System.out.println(userName+" :"+pwd);
}
/*
将JSON字符串中的两个变量的值分别赋予了两个字符串
或使用User类,拥有字段:String userName; String pwd;
可以改成:@requestBody User user
会将JSON字符串中的值赋予user中对应的属性上
*/
集合接收
- 方法形参可以是 Map、List 等集合、数组类型
- 前端数据放到集合中
- 使用较为复杂
- 使用集合接收
- 前端数据放到集合中
方法返回值
ModelAndView
-
ModelAndView
- 本次请求的处理结果
-
model
:存放请求处理完成后显示给用户的数据 -
view
:视图对象,例如 jsp 等- 对视图执行
forward
转发
- 对视图执行
-
适用
-
处理器方法处理完后需要跳转到其他资源且要在跳转资源之间传递数据
-
此时使用
ModelAndView
返回值对象- 处理器方法中需定义
ModelAndView
对象
- 处理器方法中需定义
-
-
不适用
-
处理器方法只进行跳转,不传递数据
- 或只传递数据不进行跳转
- 例如页面对 Ajax 异步响应
-
此时使用 ModelAndView 总有一部分多余
- 因此此时使用不太合适
-
String
-
返回
String
表示视图-
执行
forward
转发 -
需要先配置视图解析器
-
-
处理器方法返回的字符串可指定逻辑视图名
-
通过视图解析器解析可转换为物理视图地址
-
也可以是完整视图路径
- 不能配置视图解析器,否则路径拼接会导致异常
-
-
返回内部资源逻辑视图名
-
跳转资源为内部资源
-
视图解析器使用
InternalResourceViewResolver
内部资源视图解析器- 处理器方法返回的字符串就是跳转页面的文件名
- 无文件后缀名
- 字符串与视图解析器中的前缀、后缀相结合组成要访问的 url
- 处理器方法返回的字符串就是跳转页面的文件名
-
-
传递数据
-
方法参数对应请求中的参数
- 形参名和请求中参数名一致
-
添加形参
HttpServletRequest
-
直接使用接收的参数
-
通过 request 对象进行数据传递
request.setAttribute("name", name)
-
-
void
-
不能表示数据或视图
- 处理 Ajax 请求时可以使用
- 通过
HttpServletResponse
输出数据,响应 Ajax 请求
-
Ajax 请求服务端返回的就是数据
- 和视图无关
Object
-
处理器可以返回
Object
对象- 对象可以是 Integer、String、Map、List 或 自定义对象 等
- 但返回的对象不是作为逻辑视图,而是作为直接在页面显示的数据
- 使用对象属性的数据响应 Ajax 请求
- 对象可以是 Integer、String、Map、List 或 自定义对象 等
-
返回对象需要使用
@ResponseBody
注解- 将转换后的 JSON 数据放到响应体中
响应 Ajax 实现步骤
使用 SpringMVC 响应 Ajax 的实现步骤
-
maven 添加依赖
- SpringMVC 默认使用的 JSON 依赖是
Jackson
- 需要导入 Jackson 相关依赖
- 返回 Object 数据, 一般将数据转化为 JSON 对象后传递给浏览器页面
- SpringMVC 默认使用的 JSON 依赖是
-
在 SpringMVC 配置文件中加入
<mvc:annotation-driver>
注解驱动- 自动实现以下流程
// 将 Java 对象转换为 json 格式数据 ObjectMapper om = new ObjectMapper(); String json = om.writeValueAsString(student);
-
处理器方法上面添加
@ResponseBody
注解- 自动实现以下流程
// 输出数据,响应 Ajax 请求 response.setContentType("application/josn;character-utf-8"); PrintWriter pw = response.getWriter(); pw.println(json); // 输出 json 数据到响应体 pw.push(); // 刷新流,输出数据 pw.close(); // 关闭流
-
Json 返回值乱码解决
<!-- 注解驱动器,配置 json 格式字符编码 --> <mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <constructor-arg value="UTF-8"/> </bean> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"> <property name="failOnEmptyBeans" value="false"/> </bean> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
Object 2 json
SpringMVC 处理器方法返回 Object,转为 JSON 输出到浏览器响应 Ajax 的原理
-
<mvc:annotation-driver>
-
实现功能:完成 Java 对象到 json、xml、text 二进制 等数据格式的转换
-
通过
HttpMessageConverter
接口:消息转换器- 功能:定义了 Java 对象 转为 json、xml 等格式的方法
- 此接口有很多实现类,实现了 Java 对象转换格式的方法
StringHttpMessageConverter
- 字符串 和 json 格式转换
MappingJackson2HttpMessageConverter
- Java 对象 和 json 格式转换
// 检查处理器方法的返回值能否转为 mediaType 数据格式 boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType); // 将返回值对象调用 Jackson 中的 ObjectMapper 转为字符串 void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException;
-
注解驱动添加到
springmvc
配置文件- 自动创建
HttpMessageConverter
接口的部分实现类对象(8个)- 根据版本不同创建数量有所差别
- 不添加注解驱动只会创建更少一部分实现类对象(4个)
- 包括
MappingJackson2HttpMessageConverter
- 添加注解驱动后自动创建实现类对象
- 进行 Java 对象 和 json 格式转换
- 使用 Jackson 工具库 ObjctMapper 类完成 json 格式转换
- 自动创建
-
-
@ResponseBody
- 放在处理器方法之上
- 通过
HttpServletResponse
输出数据,响应 Ajax 请求
实现流程
- 框架对返回对象的处理流程
- 返回对象后框架会找到
HttpMessageConverter
实现类集合- 调用其中每个类的
canWrite
方法判断可以处理的类型 - 在
MappingJackson2HttpMessageConverter
类中返回 true
- 调用其中每个类的
- 调用可以使用的实现类的
write
方法- 将 Demo 对象转为 json 格式
- 使用
JackSon
的ObjectMapper
类完成 - 默认 contentType:
application/json;charset=utf-8
- 框架调用
@ResponseBody
将 json 格式数据输出到浏览器- Ajax 请求处理完成
- 返回对象后框架会找到
/**
* 方法返回 Demo 对象,通过框架转换为 json,响应 Ajax 请求
* 通过注解驱动将 Demo 对象转为 json 格式
* @ResponseBody 转为 json 格式后通过 HttpServletResponse 输出给浏览器
* 注解在方法上面
* @return
*/
@RequestMapping("demo.do")
@ResponseBody //输出 json 数据,响应 Ajax 请求
public Demo doDemo(String name, Integer age){
Demo demo = new Demo();
demo.setName(name);
demo.setAge(age);
return demo;
}
List
-
请求多个结果
- 返回 List 集合转为 Json Array 格式
- SpringMVC 框架的实现步骤一致
-
将 List 集合转为 json 数组格式
- 同时保存了 List 集合的数据顺序
-
也可以使用 map
- map 需要通过 key 获取对象
- 且map 不能排序,使用不太方便
String
-
返回字符串对象
- 此时不代表视图,而是文本数据
- 带有 注解 @ResponseBody 表示数据对象
- 不带注解表示视图
- 此时不代表视图,而是文本数据
-
处理流程
- 返回 String 后框架会找到
HttpMessageConverter
实现类集合- 调用其中每个类的
canWrite
方法判断可以处理的类型 - 在
StringHttpMessageConverter
类中返回 true
- 调用其中每个类的
- 调用可以使用的实现类的
write
方法- 将 String 对象按照指定编码格式处理
- 默认 contentType:
application/json;charset=utf-8
- 框架调用
@ResponseBody
将数据输出到浏览器- 请求处理完成
- 返回 String 后框架会找到
-
默认使用的 contentType:
"text/plain;charset=ISO-8859-1"
- 导致中文乱码
- 通过
@RequestMapping
的属性produces
指定contentType
produces = "text/plain;charset=UTF-8"
@ResponseBody
注解通过网络直接输入输出请求- 不经过过滤器,所以过滤器的编码设置无效
Controller 简单实现
package demo.controller;
import demo.vo.Demo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import java.util.ArrayList;
import java.util.List;
/**
* 声明在类上面创建 controller 对象
* 能处理请求;控制器(处理器):也叫后端控制器(back controller)
* 类中可创建多个请求处理方法,但方法处理的请求不能重复
*/
@Controller
//@RequestMapping("/demo") //所有方法最前面公共路径
public class MyControl {
/**
* 处理用户提交的请求
* springMVC 中使用方法处理
* 方法自定义,可以有多种返回值、参数
*/
/**
* 使用 doSome 方法处理 some.do 的请求
* @return ModelAndView:本次请求的处理结果
* model:请求处理完成后显示给用户的数据
* view:视图,例如 jsp 等
* @RequestMapping 类上面的注解后 url 为 /demo/some.do
* method 属性设置为只允许处理 get 请求
* 使用 @RequestMapping 修饰的方法叫做处理器方法或访问控制方法
* 可以处理请求,类似 servlet 中的 doGet、doPost
*/
@RequestMapping(value = "/some.do", method = RequestMethod.GET)
public ModelAndView doSome(String name, Integer age, HttpServletRequest request) {
// 处理 some.do 请求,调用 service 处理
ModelAndView mv = new ModelAndView();
// 使用 request添加数据,需要声明为方法参数,框架在请求的最后把数据放到 request 作用域
// request.setAttribute("message", "憨批世界");
mv.addObject("姓名", name);
mv.addObject("年龄", age);
/*
指定视图:已配置视图解析器,只需要指定逻辑名称
声明视图解析器后只需要使用文件名,前缀路径和后缀名由框架自动添加
视图解析器前缀 + 逻辑名 + 解析器后缀 = 完整路径名
框架对视图执行 forward 操作,request.getRequestDispatcher("/show.jsp").forward();
*/
mv.setViewName("show");
return mv;
}
/**
* 不指定接收请求类型,可处理所有类型请求
* @param name 参数name
* @param age 参数age
* @return 返回结果包括数据传递和视图
* @RequestParam name1 指定请求中参数 name1 赋值到 name
* @RequestParam age1 指定请求中参数 age1 赋值到 age,可以传空
*/
@RequestMapping(value = "/first.do")
public ModelAndView doFirst(@RequestParam("name1") String name,
@RequestParam(value = "age1", required = false) Integer age) {
ModelAndView mv = new ModelAndView();
mv.addObject("姓名", name);
mv.addObject("年龄", age);
mv.setViewName("first");
return mv;
}
/**
* 对象传参,将请求中形参存到对象属性中,通过对象调用参数值
* @param demo 框架自动创建对象并赋值
*/
@RequestMapping(value = "/submit.do")
public ModelAndView doSubmit(Demo demo) {
ModelAndView mv = new ModelAndView();
mv.addObject("myName", demo.getName());
mv.addObject("myAge", demo.getAge());
mv.addObject("demo", demo);
mv.setViewName("submit");
return mv;
}
/**
* 返回视图地址,不进行数据传递
* @return 返回视图的地址
*/
@RequestMapping(value = "/string.do")
public String doString() {
return "string";
}
/**
* 方法返回 demo 对象,通过框架转换为 json,响应 Ajax 请求
* 通过注解驱动将 demo 转为 json 格式
* 将 List 转为 json array 数组格式,保存 list 的顺序
* @return 返回 List 集合
* @ResponseBody 转为 json 格式之后通过 HttpServletResponse 输出给浏览器
* 注解在方法上面
*/
@RequestMapping("demo.do")
@ResponseBody //自动将 Java 转为 json 并输出响应 Ajax 请求
public List<Demo> doDemo(String name, Integer age) {
Demo demo = new Demo();
demo.setName("二狗");
demo.setAge(22);
Demo demo1 = new Demo();
List<Demo> list = new ArrayList<>();
list.add(demo);
list.add(demo1);
return list;
}
/**
* String 表示数据对象,不表示视图
* @return 返回数据对象
* 默认会使用 contentType="text/plain;charset=ISO-8859-1" 导致中文乱码
* 通过 @RequestMapping 属性 produces 指定 contentType
*/
@RequestMapping(value = "string2.do",
produces = "text/plain;charset=UTF-8")
@ResponseBody
public String doString2() {
return "作为数据对象返回";
}
}
核心技术
转发、重定向
异同
-
SpringMVC 框架把原来 Servlet 中的 请求转发和重定向操作进行了封装
-
可以使用简单的方式实现转发和重定向
-
forward
:表示转发 -
redirect
:表示重定向
-
-
共同特点:配置解析器的同时可以指定转发其他位置的视图文件
-
不与视图解析器同时工作
- 视图解析器会自动拼接视图路径
- 不在视图解析器路径下的资源无法直接转发访问
-
视图页面必须是相对于项目根的路径
-
forward
-
转发定义
-
用户发起请求到资源1
- 服务器将请求转发到资源2,由资源2作响应请求
- 访问地址栏不发生变化
-
请求一次,响应一次
-
在服务器内实现,所以资源2可以是 WEB-INF 中资源
-
-
请求转发
-
实际实现
request.getRequestDispatcher(“xx.jsp”).forward()
-
使用方式:视图路径写为:
forward:视图文件完整路径
- 显式转发
@RequestMapping(value = "/some.do", method = RequestMethod.GET) public ModelAndView doSome(String name, Integer age) { ModelAndView mv = new ModelAndView(); mv.addObject("姓名", name); mv.addObject("年龄", age); // 转发请求到 show.jsp mv.setViewName("forward:/WEB-INF/view/show.jsp"); return mv; }
-
redirect
-
重定向定义
-
用户发起请求到 资源1,资源1 回应浏览器需要访问 资源2
- 浏览器自动进行二次请求到 资源2,资源2 做出响应
- 访问地址栏发生变化,变为 资源2 地址
-
请求两次,响应两次
-
两次请求都由浏览器发起,所以不能访问 WEB-INF 中资源
-
-
redirect
实际实现:response.sendRedirect("xx.jsp")
- 使用方式:视图路径写为:
redirect:视图完整路径
- 使用方式:视图路径写为:
-
框架对 redirect 携带数据的操作
- 第一次请求传递参数,封装到 Model 中之后进行重定向操作
- 框架将 Model 中简单类型数据转为 String 使用
- 作为二次请求访问的参数
- 目的:在两次请求之间传递参数
- 但两次请求的作用域不同,取参需要在 url 中获取
- 例如:
${param.name}
、${param.age}
- 相当于
<%=request.getParameter(“name”)%>
- 例如:
- 但两次请求的作用域不同,取参需要在 url 中获取
@RequestMapping(value = "/first.do") public ModelAndView doFirst(@RequestParam("name1") String name, @RequestParam(value = "age1", required = false) Integer age) { ModelAndView mv = new ModelAndView(); mv.addObject("姓名", name); mv.addObject("年龄", age); // 二次发送请求到 test.jsp,框架将参数封装到 url 中可以获取 mv.setViewName("redirect:/test.jsp"); return mv; }
异常处理
处理方式
-
SpringMVC 采用统一、全局的异常处理
- controller 中所有异常处理都集中到一个地方
-
采用 AOP 思想:将业务逻辑和异常处理代码分开,解耦合
- 异常处理程序不影响正常程序执行
-
使用两个注解实现
@ControllerAdvice
@ExceptionHandler
处理流程
- 在
controller
中抛出异常 - 创建全局异常处理类:普通 Java 类
- 注解
@ControllerAdvice
声明为通知类,可以进行 AOP 操作 - 方法注解
@ExceptionHandler
声明为异常处理方法
- 注解
- 创建处理异常的视图页面
- 创建
SpringMVC
配置文件- 声明组件扫描器,扫描创建
@Controller
对象 - 声明组件扫描器,扫描创建
@ControllerAdvice
对象 - 声明注解驱动
- 声明组件扫描器,扫描创建
处理逻辑
- 记录异常到数据库、日志文件
- 发生时间、异常方法、异常错误内容
- 发送通知
- 将异常信息通知发送给相关人员
- 提示用户
处理实现
@ControllerAdvice
- 控制器增强,给控制器增加异常处理功能
- 注解的异常处理类上面
- 需要在 SpringMVC 配置文件声明组件扫描器
- 指定注解所在包名
@ExceptionHandler
- 注解在方法上
- 属性
value
:指定该方法处理的异常类型,Class类型值- 不指定 value
- 处理其他异常处理方法都不匹配的异常
- 一个异常处理类只能有一个,最后才匹配此方法
- 不指定 value
- 方法定义原则和 controller 一样
- 参数、返回值 等都和 controller 定义方式一样
- 方法形参:
Exception e
- 表示
controller
中抛出的异常对象 - 通过形参可获取异常发生的信息
- 表示
- 实际使用时只需要定义一个通用方法处理所有异常即可
package ssm_demo.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
@ControllerAdvice
public class MyException {
/*
* 处理 NullPointerException 异常
*/
@ExceptionHandler(NullPointerException.class)
public ModelAndView doNull(Exception e){
ModelAndView mv = new ModelAndView();
mv.addObject("type", "未知异常");
mv.addObject("message", e.getMessage());
mv.setViewName("exception");
return mv;
}
/*
* 默认处理所有类型异常,不指定注解 value 属性
* 可以处理 controller 抛出的所有类型异常
*/
@ExceptionHandler
public ModelAndView doDefault(Exception e){
ModelAndView mv = new ModelAndView();
mv.addObject("type", "未知异常");
mv.addObject("message", e.getMessage());
mv.setViewName("exception");
return mv;
}
}
拦截器
-
拦截指定的用户请求,并进行相应的预处理和后处理
-
拦截的时间点
- 处理器映射器根据用户提交的请求映射出要执行的处理器类
- 并找到要执行该处理器类的处理器适配器
- 在处理器适配器执行处理器之前
- 处理器映射器根据用户提交的请求映射出要执行的处理器类
-
在处理器映射器映射出要执行的处理器类时已经将拦截器与处理器组合为处理器执行链
- 并返回中央调度器
-
拦截器
-
SpringMVC 的一种,需要实现
HandlerInterceptor
接口- 类似于过滤器,但功能方向侧重点不同
- 过滤器用来过滤请求参数
- 设置编码字符集等工作
- 拦截器是拦截用户请求
- 做请求判断处理
- 过滤器用来过滤请求参数
- 类似于过滤器,但功能方向侧重点不同
-
特点:全局,可以对多个 controller 做拦截
- 一个项目中可以有 0 或多个拦截器,一起拦截用户请求
- 多层结构,先声明的在外层
- 先声明的拦截器 preHandle 先执行
- 执行控制器方法后先执行后声明的拦截器方法
- 框架中保存多个拦截器的是 ArrayList 集合
- 按照声明顺序放入集合
- 多层结构,先声明的在外层
- 常用:用户登录处理、权限检查、记录日志
- 一个项目中可以有 0 或多个拦截器,一起拦截用户请求
-
使用步骤
- 定义类实现
HandlerInterceptor
接口- 普通 Java 类,实现了特定接口
- 在 SpringMVC 配置文件中声明拦截器
- 声明拦截器的存在
- 定义类实现
-
执行时间
- 请求处理之前:controller 类中方法执行之前
- 控制器方法执行之后也会进行拦截
- 请求处理完成之后也会执行拦截器
-
执行顺序
- 拦截器的
preHandle
方法- 多个拦截器时先执行先声明的拦截器
- 控制器的方法
- 拦截器的
postHandle
方法- 多个拦截器先执行后声明的拦截器
- 拦截器的
afterCompletion
方法- 多个拦截器先执行后声明的拦截器
- 拦截器的
package ssm_demo.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
/**
* 预处理方法:整个项目的入口
* 执行在 控制器方法之前,用户请求先到达此方法
* 可验证用户是否登录、是否有权限访问某个连接地址(url)
* 验证失败拦截请求,请求不能被处理,到此截止
* 验证成功放行请求,此时控制器方法才能执行
* @param request
* @param response
* @param handler 被拦截的控制器对象
* @return true:通过验证 false:验证失败
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
return HandlerInterceptor.super.preHandle(request, response, handler);
}
/**
* 后处理方法
* 在处理器方法之后执行
* 可获取处理器方法返回值,且可以修改 ModelAndView 中的数据和视图
* 能影响到最后执行结果,主要对原来的结果进行 二次修正
* @param request
* @param response
* @param handler 被拦截的处理器对象
* @param modelAndView 处理器方法返回值
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
/**
* 最后执行的方法
* 在 preHandle 方法返回 true 后一定执行
* 在请求处理完成后完成:视图处理完成后,对视图进行了 forward 认为是请求完成
* 一般做资源回收工作:程序请求过程中创建的对象可在此删除以释放空间
* @param request
* @param response
* @param handler 被拦截的处理器对象
* @param ex 程序中的异常
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
多个拦截器
-
执行顺序:类似嵌套多层结构,先声明的拦截器包裹将后声明的拦截器
- 先声名的拦截器的 preHandle 方法
- 后声明的拦截器的 preHandle 方法
- 控制器的方法
- 后声明的拦截器的 postHandle 方法
- 先声明的拦截器的 postHandle 方法
- 先声明的拦截器的 afterCompletion 方法
- 后声明的拦截器的 afterCompletion 方法
-
方法执行流程
- 当外层拦截器的 preHandle 方法返回 false
- 请求到此结束,后面所有方法不再执行
- 当外层拦截器的 preHandle 方法返回 true
- 内层若有拦截器 preHandle 方法返回 false
- preHandle 方法返回 ture 的拦截器的 afterCompletion 方法一定执行
- 其他方法不再执行
- 内层若有拦截器 preHandle 方法返回 false
- 当外层拦截器的 preHandle 方法返回 false
区别过滤器
- 过滤器是 servlet 中对象
- 拦截器是框架中对象
- 过滤器是实现 Filter 接口的对象
- 拦截器实现 HandIerInterceptor 接口
- 过滤器用来设置 request、response 的参数、属性;侧重对数据过滤
- 拦截器用来验证请求,能截断请求
- 过滤器在拦截器之前执行
- 过滤器是 tomcat 服务器创建的对象
- 拦截器是 SpringMVC 容器创建的对象
- 过滤器只有一个执行时间点
- 拦截器有三个执行时间点
- 过滤器可处理 jsp、js、html 等
- 拦截器侧重拦截 controller 对象
- 若请求不能被 DispatcherServlet 接收,则不会执行拦截器
- 拦截器侧重拦截 controller 对象
- 过滤器过滤 servlet 请求响应
- 拦截器拦截 处理请求方法 方法执行
文件上传
添加依赖
<!-- 文件上传支持 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
配置 Spring
<!-- 文件上传配置 -->
<bean id="resolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 请求的编码格式,必须和 jsp 的 pageEncoding属性一致,以便正常填写表单 -->
<property name="defaultEncoding" value="UTF-8"/>
<!-- 阈值,低于此值只保留在内存中。超过后生成硬盘的临时文件 -->
<property name="maxInMemorySize" value="40960"/>
<!-- 上传文件大小限制 10485760=10M -->
<property name="maxUploadSize" value="10485760"/>
</bean>
controller 方法:上传文件
- 将文件从本地上传到服务器
- 即从客户端接收文件
@RequestMapping("/upload")
public String fileUpload(@RequestParam("file")CommonsMultipartFile file,
HttpServletRequest request) throws IOException {
//获取上传的文件名
String filename = file.getOriginalFilename();
//若文件名为空直接返回首页
if ("".equals(filename) || filename == null){
return "redirect:index.jsp";
}
//上传文件存放的路径
String path = request.getServletContext().getRealPath("/upload");
//创建文件对象
File filepath = new File(path);
//判断文件路径是否存在,不存在时直接创建
if (!filepath.exists()){
filepath.mkdirs();
}
//获取文件输入流
InputStream in = file.getInputStream();
//创建文件输出流
OutputStream out = new FileOutputStream(new File(filepath,filename));
int len = 0;
byte[] buffer = new byte[1024];
while ((len = in.read(buffer)) != -1){
out.write(buffer, 0, len); // 读取文件并存放到指定路径
}
out.close();
in.close();
return "redirect:index.jsp";
}
//使用工具类方法直接转存文件
@RequestMapping("/upload2")
public String fileUpload2(@RequestParam("file")CommonsMultipartFile file,
HttpServletRequest request) throws IOException {
// 获取上传路径
String path = request.getServletContext().getRealPath("/upload");
// 创建文件对象
File filepath = new File(path);
// 判断文件路径是否存在,不存在时直接创建
if (!filepath.exists()) {
filepath.mkdirs();
}
// 文件转存到指定路径
file.transferTo(new File(filepath+"/"+file.getOriginalFilename()));
return "redirect:/index.jsp";
}
下载文件
@RequestMapping("download")
public String download(HttpServletResponse response,
HttpServletRequest request) throws IOException {
// 获取下载文件的地址
String realPath = request.getServletContext().getRealPath("/upload");
// 定义文件名
String filename= "";
// 设置 response 响应头
response.reset(); // 设置页面不缓存,清空 buffer
response.setCharacterEncoding("UTF-8"); // 字符编码
response.setContentType("multipart/form-date"); // 二进制转化数据
// 设置响应头
response.setHeader("Content-Disposition", "attachment;filename="
+ URLEncoder.encode(filename, "UTF-8"));
// 创建文件对象
File file = new File(realPath, filename);
// 输入流读取文件
InputStream in = new FileInputStream(file);
// 输出流写出文件
OutputStream out = response.getOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
// 循环写出
while ((len = in.read(buffer)) != -1){
out.write(buffer, 0, len);
out.flush();
}
out.close();
in.close();
return null;
}
执行原理
- 浏览器 发出请求:
some.do
- 中央调度器
DispatcherServlet
接收请求
- 中央调度器
- 请求转到处理器映射器
HandlerMapping
- 找到并获取处理
some.do
请求的controller
对象
- 找到并获取处理
- 获取的对象放到 处理器执行链 返回中央调度器
- 将 处理器执行链 交给 处理器适配器
HandlerAdapter
- 执行处理器方法
- 返回 执行结果
ModelAndView
到处理器适配器 - 适配器将
ModelAndView
返回到到中央调度器 - 中央调度器将
ModelAndView
交给 视图解析器- 组成视图的完整路径,并创建视图对象
View
- 组成视图的完整路径,并创建视图对象
- 视图解析器返回
View
对象到中央调度器 - 中央调度器调用执行
View
的方法- 将
Model
数据放到request
作用域,执行对象视图中的forward
- 将
- 响应浏览器,完成请求
处理器
自定义 controller 类,定义处理请求的方法
DispatcherServlet
-
核心模块,连接各大模块,调度执行请求
-
核心方法:
doDispatch()
;完成各种请求protected void doDispatch(HttpServletRequest request, HttpServletResponse response){ // 接收请求对象 HttpServletRequest processedRequest = request; // 处理器执行链对象 HandlerExecutionChain mappedHandler = null; // 调用映射器得到处理器执行链 mappedHandler = this.getHandler(processedRequest); // 调用适配器 HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler()); // 执行处理器方法 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); }
Handlemappeing
- 处理器映射器
- SpringMVC 框架中的一种对象
- 实现了
HandlerMapping
接口的类都叫做映射器(有多个)
- 实现了
- 注解应使用映射器:
RequestMappingHandlerMapping
- SpringMVC 框架中的一种对象
- 用来从 SpringMVC 容器中获取处理器对象
- 将获取的处理器对象放到处理器执行链保存
HandlerExecutionChain
- 处理器执行链
HandlerExecutionChain
类
- 属性:
private final Object handler;
- 存放处理器对象
- 属性:
private final List<HandlerInterceptor> interceptorList;
- 存放项目中所有拦截器对象
HandlerAdapter
- 处理器适配器
- SpringMVC 框架中的对象
- 实现
HandlerAdapter
接口的是处理器适配器(有多个) - 一个映射器对应一个适配器
- 实现
- SpringMVC 框架中的对象
- 作用:执行处理器方法
- 调用
contrller
中的请求处理方法,得到返回值ModelAndView
- 调用
ViewResolver
- 视图解析器
- SpringMVC 中的对象
- 实现
ViewResolver
接口的是视图解析器 - 可以声明多个
- 实现
- SpringMVC 中的对象
- 作用:组成完整视图路径
- 使用前缀、后缀;并创建
View
对象
- 使用前缀、后缀;并创建
View
接口:表示视图- 框架中 jsp、html 由 View 和 其实现类表示
InternalResourceView
:视图类,表示 jsp 文件- 由视图解析器创建其对象
- 对象属性:url 表示视图路径