一、Spring MVC概述
Spring MVC是由Spring官方提供的基于MVC设计理念,通过对Servlet封装实现MVC控制的的web组件(框架)
1.1 Spring MVC优势
- 严格遵守是MVC分层思想
- 采用松耦合、插件式结构——相比较其他的MVC框架来说更加灵活、更具扩展性
- SpringMVC是一个基于Spring的web组件,提供了一套完善的MVC注解
- SpringMVC在映射处理器插件、视图解析器插件都提供了多种处理方式,可以灵活配置
- SpringMVC对RESTful规范的URL设计提供了良好的支持
1.2 Spring MVC核心工作
- 接收、解析用户请求
- 调用业务类处理请求(业务类)
- 解析响应结果、绑定数据、响应用户
二、Spring MVC框架部署
2.1 创建基于Maven的web工程
2.2 添加SpringMVC所需的依赖
- spring-webmvc
- spring-aspects
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
2.3 创建SpringMVC配置文件
- 在resources创建名为spring-servlet.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:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 声明使用注解 -->
<context:annotation-config/>
<!-- 指定注解扫描范围 -->
<context:component-scan base-package="com.qfedu"/>
<!-- 声明MVC也使用注解配置 -->
<mvc:annotation-driven/>
</beans>
2.4 在web.xml中配置SpringMVC前端控制器
<?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>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
三、Spring MVC使用
案例:添加图书信息
3.1 准备工作
由于配置前端控制器DispatcherServlet时url-pattern的值为
/*
,会拦截所有请求,包括.jsp,在此案例中将/*
暂时修改为*.do
-
创建book-add.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h4>添加图书信息</h4> <form action="book/add.do" method="post"> <p>编号:<input type="text" name="bookId"/></p> <p>名称:<input type="text" name="bookName"/></p> <p>作者:<input type="text" name="bookAuthor"/></p> <p>价格:<input type="text" name="bookPrice"/></p> <p>日期:<input type="text" name="bookDate"/></p> <p>描述:<input type="text" name="bookDesc"/></p> <p><input type="submit" value="提交"/></p> </form> </body> </html>
3.2 创建控制器
在SpringMVC中,将处理用户请求的类称之为“控制器”
- 创建处理用户请求的类 BookController:
@Controller
声明此类为SpringMVC控制器类@RequestMapping
声明此控制类器的请求路径
- 在类中定义处理请求的方法 add , 返回值为ModelAndView类型,通过ModelAndView对象封装响应数据及页面路径
@RequestMapping
声明此处理请求方法的路径
@Controller
@RequestMapping("/book")
public class BookController {
@RequestMapping("/add.do")
public ModelAndView add(Book book){
System.out.println("BookController~~~~~~add");
System.out.println(book);
ModelAndView modelAndView = new ModelAndView("/tips.jsp");
modelAndView.addObject("tips","提交图书成功!");
return modelAndView;
}
}
3.3 页面提交数据到控制器
<form action="book/add.do" method="post">
...
</form>
四、Spring MVC的请求处理流程
4.1 SpringMVC请求流程分析
①前端放松请求被前端控制器DispatcherServlet组件拦截
②前端控制器调用处理器映射HandlerMapping组件对请求URL进行解析,解析之后返回调用链给前端控制器
③前端控制器调用处理器适配器HandlerAdapter组件处理调用链
④处理器适配器基于反射通过适配器模式调用`控制器/处理器`处理用户请求,并返回数据及视图(ModelAndView,String)信息给处理器适配器
⑤处理器适配器封装视图及数据到ModelAndView对象,将ModelAndView对象返回给前端控制器
⑥前端控制器调用视图解析器ViewResolver组件进行解析(分离视图资源和数据资源),将解析结果返回给前端控制器
⑦前端控制器调用视图View组件对视图和数据进行渲染,将渲染结果(html)返回给前端控制器
⑧前端控制器将渲染响应给用户浏览器
4.2 SpringMVC核心组件
-
DispatcherServlet
前端控制器、总控制器- 接收用户请求
- 协同各个组件工作
- 响应浏览器
-
HandlerMapping
处理器映射- 负责根据用户的请求url找到对应控制器/处理器
- 此组件是可以配置的,不同的处理器映射器解析URL的方式不一样
-
HandlerAdapter
处理器适配器- 按照处理器映射对请求URL解析的调用链,通过适配器模式完成Handler的调用
-
Handler
处理器- 处理用户请求的类,由程序员进行开发,处理器也称之为控制器(Controller)
-
ModelAndView
视图模型- 用于封装响应用户请求的视图及数据的组件
- ModelAndView = Model + View
-
ViewResolver
视图解析器- 对视图模型ModelAndView进行解析
- 此组件也是可以配置的,不同的视图解析器对控制器响应的视图路径解析方式是不同的
-
View
视图- 完成视图的数据渲染
五、Spring MVC开发使用细节
5.1 静态资源配置
在web.xml中配置SpringMVC的前端控制器时,如果将url-pattern设置为
/*
,他将会拦截所有请求,包括jsp及所有的静态资源(html\js\css\图片)。如何放行静态资源呢?
- 设置url-pattern拦截规则为
*.do
,使用此配置方式需要在所有的控制类的方法中配置路径时都要添加.do后缀;- 【√】设置url-pattern拦截规则为
/
,也表示拦截所有请求,但是会放行.jsp请求;但是会拦截其他的静态资源(html\js\css\图片)
在项目开发中SpringMVC前端控制器的配置通常使用/
,对于需要放行的静态资源只需添加配置即可:
<!--spring-servlet.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:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.qfedu"/>
<mvc:annotation-driven/>
<!-- 配置SpringMVC前端控制器放行的静态资源 -->
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/images/**" location="/images/"/>
<mvc:resources mapping="/page/**" location="/page/"/>
</beans>
5.2 创建控制器
5.2.1 创建控制器类
@Controller
声明此类时一个控制类,可以处理http请求@RequestMapping
声明此控制类的请求路径,非必须
@Controller
@RequestMapping("/book")
public class BookController {
}
5.2.2 创建处理请求的方法
- 在控制类中创建一个方法,返回类型可以是:
- 当此方法处理同步请求(String、ModelAndView)
- 当此方法处理异步请求(void、任何对象)
- 控制器类中处理请求的方法通过参数注入请求传递的数据,所以控制器方法参数类型根据用户请求提交的数据来决定
@RequestMapping
声明此方法的请求路径
@Controller
@RequestMapping("/book")
public class BookController {
/**
* 处理同步请求
*/
@RequestMapping("/add")
public ModelAndView add(Book book){
System.out.println("---------------------");
return null;
}
/**
* 处理异步请求
*/
@RequestMapping("/list")
public void list(){
System.out.println("---------------------");
}
}
5.3 前端请求控制器类中方法
-
同步请求
<form action="book/add" method="post"> <p>编号:<input type="text" name="bookId"/></p> <p>名称:<input type="text" name="bookName"/></p> <p>作者:<input type="text" name="bookAuthor"/></p> <p>价格:<input type="text" name="bookPrice"/></p> <p>日期:<input type="text" name="bookDate"/></p> <p>描述:<input type="text" name="bookDesc"/></p> <p><input type="submit" value="提交"/></p> </form> <a href="book/add?bookId=1&bookName=Java">请求</a>
-
异步请求
<button id="listBtn">获取图书信息</button> <script type="text/javascript" src="js/jquery-3.6.0.min.js"/> <script type="text/javascript"> $("#listBtn").click(function(){ $.post("book/list",{pageNum:1,pageSize:10},function(res){ },"json"); }); </script>
5.4 控制器类接收前端提交的数据
控制器类中的方法接收前端数据
5.4.1 @RequestParam 接收请求行数据
-
前端提交数据:
<form action="book/add" method="get|post"> <p>编号:<input type="text" name="bookId"/></p> <p>名称:<input type="text" name="bookName"/></p> <p>作者:<input type="text" name="bookAuthor"/></p> <p>价格:<input type="text" name="bookPrice"/></p> <p>日期:<input type="text" name="bookDate"/></p> <p>描述:<input type="text" name="bookDesc"/></p> <p><input type="submit" value="提交"/></p> </form> <!--表单的post提交 ---> <button id="listBtn">获取图书信息</button> <script type="text/javascript" src="js/jquery-3.6.0.min.js"></script> <script type="text/javascript"> $("#listBtn").click(function(){ //$.post("book/add",{bookId:1,bookName:"Java"},function(res){ // //},"json"); var obj = {bookId:1,bookName:"Java"}; $.ajax({ url:"book/add", type:"post", data:obj, success:function(res){ } }); }); </script>
-
在接收请求的控制器类的方法中定义属性,通过
@RequestParam
声明接收数据的key@RequestMapping("/add") public ModelAndView add(@RequestParam("bookId") int bid, @RequestParam("bookName") String bname){ System.out.println("---------------------"); return null; }
-
如果控制器类方法的参数名与提交数据的key一致,
@RequestParam
可以省略@RequestMapping("/add") public ModelAndView add(int bookId,String bookName){ System.out.println("---------------------"); return null; }
5.4.2 @RequestBody 接收请求正文数据
通过ajax的post方式提交json格式字符串
-
前端请求
<button id="listBtn">获取图书信息</button> <script type="text/javascript" src="js/jquery-3.6.0.min.js"></script> <script type="text/javascript"> $("#listBtn").click(function(){ var obj = {bookId:1,bookName:"Java"}; var str = JSON.stringify(obj); $.ajax({ url:"book/add", type:"post", contentType:"application/json", data:str, success:function(res){ } }); }); </script>
-
处理器方法接收数据
- 添加jackson依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.1</version>
</dependency>
- 在接收请求的方法参数中添加@RequestBody注解接收并解析数据
@RequestMapping("/add")
public void add(@RequestBody Book book){
System.out.println("----add");
}
5.4.3 @RequestHeader 接收请求头数据
-
前端请求头提交数据
<button id="listBtn">获取图书信息</button> <script type="text/javascript" src="js/jquery-3.6.0.min.js"></script> <script type="text/javascript"> $("#listBtn").click(function(){ var obj = {bookId:1,bookName:"Java"}; var str = JSON.stringify(obj); $.ajax({ url:"book/add", type:"post", contentType:"application/json", data:str, headers:{ key1:"value1", key2:"value2" }, success:function(res){ console.log(res); } }); }); </script>
-
控制器方法通过@RequestHeader接收请求头数据
@RequestMapping("/add") public void add(@RequestBody Book book, @RequestHeader("key1") String key1, @RequestHeader("key2") String key2){ System.out.println("----add"); }
ue1",
key2:“value2”
},
success:function(res){
console.log(res);
}
});
});
```
-
控制器方法通过@RequestHeader接收请求头数据
@RequestMapping("/add") public void add(@RequestBody Book book, @RequestHeader("key1") String key1, @RequestHeader("key2") String key2){ System.out.println("----add"); }