SpringMVC 简介
MVC 模式
MVC 是软件工程中的一种软件架构模式,它是一种分离业务逻辑与显示界面的开发思想。
* M(model)模型:处理业务逻辑,封装实体
* V(view) 视图:展示内容
* C(controller)控制器:负责调度分发(1.接收请求、2.调用模型、3.转发到视图)
SpringMVC 概述
SpringMVC 是一种基于 Java 的实现 MVC 设计模式的轻量级 Web 框架,属于Spring Framework 的后续产品,已经融合在 Spring Web Flow 中。
SpringMVC 已经成为目前最主流的 MVC 框架之一,并且随着 Spring 3.0 的发布,全面超越 Struts 2,成为最优秀的 MVC 框架。它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持 RESTful 编程风格的请求。
SpringMVC 的框架就是封装了原来 Servlet 中的共有行为;例如:参数封装,视图转发等。
SpringMVC 快速入门
需求:客户端发起请求,服务器接收请求,执行逻辑并进行视图跳转。
步骤分析:
- 创建web项目,导入 SpringMVC 相关坐标
- 配置 SpringMVC 前端控制器
DispatcherServlet
- 编写 Controller 类和视图页面
- 使用注解配置 Controller 类中业务方法的映射地址
- 配置 SpringMVC 核心文件 spring-mvc.xml
创建 web 项目,导入 SpringMVC 相关坐标
<packaging>warpackaging>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8maven.compiler.encoding>
<java.version>1.11java.version>
<maven.compiler.source>1.11maven.compiler.source>
<maven.compiler.target>1.11maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.1.5.RELEASEversion>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.2version>
<scope>providedscope>
dependency>
...
dependencies>
配置 SpringMVC 前端控制器 `DispatcherServlet`
<?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">
<servlet>
<servlet-name>DispatcherServletservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:spring-mvc.xmlparam-value>
init-param>
<load-on-startup>2load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>DispatcherServletservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
编写 Controller 类和视图页面
UserController.java
public class UserController {
public String quick() {
// 业务处理
System.out.println("SpringMVC Quick Start...");
// 页面跳转 请求转发
return "/WEB-INF/pages/success.jsp";
}
}
/WEB-INF/pages/success.jsp
"text/html;charset=UTF-8" language="java" %>
SUCCESS
success... ${username}
"Success...");%>
使用注解配置 Controller 类中业务方法的映射地址
@Controller
public class UserController {
@RequestMapping("/quick")
public String quick() {
System.out.println("SpringMVC Quick Start...");
return "/WEB-INF/pages/success.jsp";
}
}
配置 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.renda.controller"/>
beans>
web 工程执行流程
客户端(浏览器)发送请求到 Tomcat 服务器,Tomcat 服务器发送响应到客户端。
服务器的 Tomcat 引擎:
- 接受客户端请求,解析请求资源地址
- 创建代表请求的 request 对象
- 创建代表响应 response 对象
- 调用目标资源
- 获得 response 中的内容,组装成 HTTP 响应返回客户端
服务器的 Web 应用:
- 获得请求资源地址
- 解析映射地址,找到对应的处理器(Controller)
- 处理器执行对应的方法(进行业务逻辑以及视图跳转操作),获取被访问的真实资源
小结
* SpringMVC 是对 MVC 设计模式的一种实现,属于轻量级的 WEB 框架。
* SpringMVC 的开发步骤:
1.创建 web 项目,导入 SpringMVC 相关坐标
2.配置 SpringMVC 前端控制器 DispatcherServlet
3.编写 Controller 类和视图页面
4.使用注解配置 Controller 类中业务方法的映射地址
5.配置 SpringMVC 核心文件 spring-mvc.xml
SpringMVC 组件概述
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 组件解析
1. 前端控制器:DispatcherServlet
用户请求到达前端控制器,它就相当于 MVC 模式中的 C;DispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求;DispatcherServlet 的存在降低了组件之间的耦合性。
2. 处理器映射器:HandlerMapping
HandlerMapping 负责根据用户请求找到 Handler 即处理器;SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式、实现接口方式、注解方式等。
3. 处理器适配器:HandlerAdapter
通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
4. 处理器:Handler【**开发者编写**】
它是开发中要编写的具体业务控制器;由 DispatcherServlet 把用户请求转发到 Handler;由 Handler 对具体的用户请求进行处理。
5. 视图解析器:ViewResolver
View Resolver 负责将处理结果生成 View 视图;View Resolver 首先根据逻辑视图名解析成物理视图名,即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
6. 视图:View 【**开发者编写**】
SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等。最常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
7. SpringMVC 中的三大组件是什么?
处理器映射器 HandlerMapping;
处理器适配器 HandlerAdapter;
视图解析器 ViewResolver;
如果是四大组件,则加上前端控制器 DispatcherServlet。
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.renda.controller"/>
<mvc:annotation-driven/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/">property>
<property name="suffix" value=".jsp">property>
bean>
beans>
UserController.java
@RequestMapping("/quick")
public String quick() {
System.out.println("SpringMVC Quick Start...");
// 页面跳转 请求转发 返回逻辑视图名
return "success";
}
SpringMVC 注解解析
`@Controller`
SpringMVC 基于 Spring 容器,所以在进行 SpringMVC 操作时,需要将 Controller 存储到 Spring 容器中,如果使用 @Controller
注解标注的话,就需要使用:
<context:component-scan base-package="com.renda.controller"/>
注意配置 SpringMVC 的 base package 只扫描 web 层的包,其它包交给 Spring 容器扫描;这样 SpringMVC 的容器就相当于是 Spring 容器的一个子容器。
`@RequestMapping`
* 作用:用于建立请求 URL 和处理请求方法之间的对应关系
* 位置:
1. 类上:请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录;写的话需要以 / 开头。
它出现的目的是为了使 URL 可以按照模块化管理:
用户模块
/user/add
/user/update
/user/delete
...
账户模块
/account/add
/account/update
/account/delete
2. 方法上:请求 URL 的第二级访问目录,和一级目录组成一个完整的 URL 路径。
* 属性:
1. value:用于指定请求的 URL;它和 path 属性的作用是一样的
2. method:用来限定请求的方式
3. params:用来限定请求参数的条件
例如:
params={"accountName"} 表示请求参数中必须有 accountName
params={"money!100"} 表示请求参数中 money 不能是100
@Controller
@RequestMapping("/user") //一级访问目录
public class UserController {
/**
* http://localhost:8080/springmvc_quickstart/user/quick?accountName=renda
*
* path :作用等同于 value,同样是设置方法的映射地址
* method:用来限定请求的方式 RequestMethod.POST: 只能以 post 的请求方式访问该访问,其他请求方式会报错
* params:用来限定请求参数的条件 params={"accountName"} 表示请求参数中必须有 accountName
*/
@RequestMapping(
path = "/quick", // 二级访问目录
method = {RequestMethod.POST, RequestMethod.GET},
params = {"accountName"})
public String quick() {
// 业务处理
System.out.println("SpringMVC Quick Start...");
// 页面跳转 请求转发 返回逻辑视图名
return "success";
}
}
小结
* SpringMVC的三大组件
处理器映射器:HandlerMapping
处理器适配器:HandlerAdapter
视图解析器:View Resolver
* 开发者编写
处理器:Handler
视图:View
SpringMVC 的请求
请求参数类型介绍
客户端请求参数的格式是:name=value&name=value ...
服务器要获取请求的参数的时候要进行类型转换,有时还需要进行数据的封装
SpringMVC 可以接收如下类型的参数:
- 基本类型参数
- 对象类型参数
- 数组类型参数
- 集合类型参数
获取基本类型参数
Controller 中的业务方法的参数名称要与请求参数的 name 一致,参数值会自动映射匹配。并且能自动做类型转换;自动的类型转换是指从 String 向其他类型的转换。
requestParam.jsp
"${pageContext.request.contextPath}/user/simpleParam?id=1&username=杰克">
基本类型参数
在 UserController
中添加方法
@RequestMapping("/simpleParam")
public String simpleParam(Integer id, String username) {
System.out.println(id);
System.out.println(username);
return "success";
}
获取对象类型参数
Controller 中的业务方法参数的 POJO 属性名与请求参数的 name 一致,参数值会自动映射匹配。
requestParam.jsp
"${pageContext.request.contextPath}/user/pojoParam" method="post">
编号:"text" name="id">
用户名:"text" name="username">"submit" value="对象类型参数">
创建 User
类
public class User {
private Integer id;
private String username;
// setter getter...
}
在 UserController
中添加方法
@RequestMapping("/pojoParam")
public String pojoParam(User user){
System.out.println(user);
return "success";
}
中文乱码过滤器
当 post 请求时,数据会出现乱码,可以在 web.xml 设置一个过滤器来进行编码的过滤。
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
获取数组类型参数
Controller 中的业务方法数组名称与请求参数的 name 一致,参数值会自动映射匹配。
requestParam.jsp
"${pageContext.request.contextPath}/user/arrayParam" method="post">
编号:"checkbox" name="id" value="1">1"checkbox" name="ids" value="2">2"checkbox" name="ids" value="3">3"checkbox" name="ids" value="4">4"submit" value="数组类型参数">
在 UserController
中添加方法
@RequestMapping("/arrayParam")
public String arrayParam(Integer[] ids){
System.out.println(Arrays.toString(ids));
return "success";
}
获取集合(复杂)类型参数
获得集合参数时,要将集合参数包装到一个 POJO 中才可以。
requestParam.jsp
"${pageContext.request.contextPath}/user/queryParam" method="post">
搜索关键字:"text" name="keyword">
user对象:"text" name="user.id" placeholder="编号">"text" name="user.username" placeholder="姓名">
list集合:
元素1:"text" name="userList[0].id" placeholder="编号">"text" name="userList[0].username" placeholder="姓名">
元素2:"text" name="userList[1].id" placeholder="编号">"text" name="userList[1].username" placeholder="姓名">
Map集合:
元素1:"text" name="userMap['u1'].id" placeholder="编号">"text" name="userMap['u1'].username" placeholder="姓名">
元素2:"text" name="userMap['u2'].id" placeholder="编号">"text" name="userMap['u2'].username" placeholder="姓名">"submit" value="复杂类型">
创建 QueryVo
类
public class QueryVo {
private String keyword;
private User user;
private List userList;private Map userMap;// setter getter...
}
在 UserController
中添加方法
@RequestMapping("/queryParam")
public String queryParam(QueryVo queryVo){
System.out.println(queryVo);
return "success";
}
自定义类型转换器
SpringMVC 默认已经提供了一些常用的类型转换器。例如:客户端提交的字符串转换成 INT 型进行参数设置,日期格式类型要求为:yyyy/MM/dd
不然的话会报错;对于特有的行为,SpringMVC 提供了自定义类型转换器方便开发者自定义处理。
requestParam.jsp
"${pageContext.request.contextPath}/user/converterParam" method="post">
生日:"text" name="birthday">"submit" value="自定义类型转换器">
配置自定义日期转换 DateConverter
public class DateConverter implements Converter<String, Date> {
/**
* s 就是表单传递过来的请求参数,如 2012-12-12
*/
@Override
public Date convert(String s) {
// 将日期字符串转换成日期对象,进行返回
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = simpleDateFormat.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
spring-mvc.xml
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.renda.converter.DateConverter"/>
set>
property>
bean>
<mvc:annotation-driven conversion-service="conversionService"/>
在 UserController
中添加方法
@RequestMapping("/converterParam")
public String converterParam(Date birthday){
System.out.println(birthday);
return "success";
}
相关注解
`@RequestParam`
当请求的参数 name 名称与 Controller 的业务方法参数名称不一致时,就需要通过 @RequestParam
注解显示的绑定
requestParam.jsp
"${pageContext.request.contextPath}/user/findByPage?pageNo=2">
分页查询
在 UserController
中添加方法
/**
* name:匹配页面传递参数的名称
* defaultValue:设置参数的默认值
* required:设置是否必须传递该参数,默认值为 true;如果设置了默认值,值自动改为 false
*/
@RequestMapping("findByPage")
public String findByPage(
@RequestParam(name = "pageNo", defaultValue = "1", required = false) Integer pageNum,
@RequestParam(defaultValue = "5") Integer pageSize) {
System.out.println(pageNum);
System.out.println(pageSize);
return "success";
}
`@RequestHeader`
获取请求头的数据。
在 UserController
中添加方法
@RequestMapping("/requestHeader")
public String requestHead(@RequestHeader("cookie") String cookie){
System.out.println(cookie);
return "success";
}
`@CookieValue`
获取 cookie
中的数据。
在 UserController
中添加方法
@RequestMapping("/cookieValue")
public String cookieValue(@CookieValue("JSESSIONID") String jSessionId){
System.out.println(jSessionId);
return "success";
}
获取 Servlet 相关 API
SpringMVC 支持使用原始 Servlet API 对象作为控制器方法的参数进行注入,常用的对象如下:
@RequestMapping("/servletAPI")
public String servletApi(HttpServletRequest request, HttpServletResponse response, HttpSession session){
System.out.println(request);
System.out.println(response);
System.out.println(session);
return "success";
}
SpringMVC 的响应
SpringMVC 响应方式介绍
页面跳转:
- 返回字符串逻辑视图
void
原始ServletAPI
ModelAndView
返回数据:
- 直接返回字符串数据
- 将对象或集合转为
json
返回
返回字符串逻辑视图
直接返回字符串:此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转到指定页面
@RequestMapping("/returnString")
public String returnString() {
return "success";
}
`void` 原始 `ServletAPI`
可以通过 request、response 对象实现响应
index.jsp
"text/html;charset=UTF-8" language="java" %>
Index
Hello ${username}
在 UserController
中添加方法
@RequestMapping("/returnVoid")
public void returnVoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/* 直接返回数据 */
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("张人大");
request.setAttribute("username", "Renda");
// 借助 request 对象完成请求转发,一次请求
// request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request, response);
// request.getRequestDispatcher("/index.jsp").forward(request, response);
// 借助 response 对象完成重定向,两次请求。WEB-INF - 安全目录:不允许外部请求直接访问该目录资源,只可以进行服务器内部转发
// response.sendRedirect(request.getContextPath() + "/index.jsp");
}
转发和重定向
企业开发一般使用返回字符串逻辑视图实现页面的跳转,这种方式其实就是请求转发;也可以写成:forward 转发。如果用了 forward,则路径必须写成实际视图 URL,不能写逻辑视图。它相当于:
request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response)
使用请求转发,既可以转发到 JSP,也可以转发到其他的控制器方法。
@RequestMapping("/forward")
public String forward(Model model){
// 在模型中设置一些值
model.addAttribute("username","RendaZhang");
// 使用请求转发,既可以转发到 jsp,也可以转发到其他的控制器方法
// return "forward:/product/findAll";
return "forward:/WEB-INF/pages/success.jsp";
}
Redirect 重定向:可以不写虚拟目录,SpringMVC 框架会自动拼接,并且将 Model 中的数据拼接到 URL 地址上;重定向的目标 JSP 页面不能写在 WEB-INF 目录中,否则无法找到。
@RequestMapping("/redirect")
public String redirect(Model model) {
// 底层使用的还是 request.setAttribute("username","RENDA"),
// 域范围是一次请求,所以重定向后,请求发生了变化,请求域的值无法获取
model.addAttribute("username", "RENDA");
return "redirect:/index.jsp";
}
`ModelAndView`
方式一
在 Controller 中方法创建并返回 ModelAndView
对象,并且设置视图名称
/**
* model:模型:作用封装存放数据
* View :视图:用来展示数据
*/
@RequestMapping("/returnModelAndView")
public ModelAndView returnModelAndView(){
ModelAndView modelAndView = new ModelAndView();
// 设置模型数据
modelAndView.addObject("username","modelAndView 方式一");
// 设置视图名称。视图解析器解析 modelAndView 拼接前缀和后后缀
modelAndView.setViewName("success");
return modelAndView;
}
方式二
在 Controller 中方法形参上直接声明 ModelAndView
,无需在方法中自己创建,在方法中直接使用该对象设置视图,同样可以跳转页面
@RequestMapping("/returnModelAndView2")
public ModelAndView returnModelAndView2(ModelAndView modelAndView){
// 设置模型数据
modelAndView.addObject("username","modelAndView 方式二");
// 设置视图名称。视图解析器解析 modelAndView 拼接前缀和后后缀
modelAndView.setViewName("success");
return modelAndView;
}
`@SessionAttributes`
如果在多个请求之间共用数据,则可以在控制器类上标注一个 @SessionAttributes
,配置需要在 session
中存放的数据范围,SpringMVC 将存放在 model
中对应的数据暂存到 HttpSession
中。
注意:@SessionAttributes
只能定义在类上
@Controller
@RequestMapping("/user") //一级访问目录
@SessionAttributes("username") // 向 request 域中(model)中存入 key 为 username 时,会同步到 session 域中
public class UserController {
...
@RequestMapping("/forward")
public String forward(Model model) {
// 在模型中设置一些值
model.addAttribute("username", "RendaZhang");
// 使用请求转发,既可以转发到 jsp,也可以转发到其他的控制器方法
// return "forward:/product/findAll";
return "forward:/WEB-INF/pages/success.jsp";
}
...
@RequestMapping("/returnString")
public String returnString(){
return "success";
}
}
小结
* 页面跳转采用返回字符串逻辑视图
forward 转发
可以通过Model向request域中设置数据
redirect 重定向
直接写资源路径即可,虚拟目录springMVC框架自动完成拼接
* 数据存储到 request 域中
Model model
model.addAttribute("username", "子慕");
静态资源访问的开启
requestParam.jsp
...
...
当有静态资源需要加载时,比如 jQuery 文件,通过谷歌开发者工具抓包发现,没有加载到 jQuery 文件,原因是 SpringMVC 的前端控制器 DispatcherServlet
的 url-pattern
配置的是 /
(默认配置),代表对所有的静态资源都进行处理操作,这样就不会执行 Tomcat 内置的 DefaultServlet
处理,可以通过以下两种方式在 spring-mvc.xml 指定放行静态资源。
方式一:放行指定的静态资源
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/img/**" location="/img/"/>
方式二:放行全部的静态资源
<mvc:default-servlet-handler/>