SpringMVC-01
1、SpringMVC的概述
Spring MVC框架是一个开源的Java平台,为开发强大的基于JavaWeb应用程序提供全面的基础架构支持,并且使用起来非常简单容易。
Spring web MVC框架提供了MVC(模型 - 视图 - 控制器)架构,用于开发灵活和松散耦合的Web应用程序的组件。 MVC模式使应用程序的不同组件(输入逻辑,业务逻辑和UI逻辑)合理有效的分离,同时又有效的将各组件组合一起完成功能。
· 模型(Model) 封装了应用程序数据,通常它们将由POJO类组成。
· 视图(View) 负责渲染模型数据,一般来说它负责生成客户端浏览器可以解释HTML输出。
· 控制器(Controller) 负责处理用户请求并构建适当的模型,并将其传递给视图进行渲染。
2、SpringMVC的核心DispatcherServlet程序
SpringMVC的核心是一个前端控制器。它负责将收到的所有请求。分发给不同模块的Controller控制器,去接收业务处理
其实这个前端控制器,它就是一个Servlet程序。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <servlet>
<servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup> </servlet>
<servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
|
3、SpringMVC的第一个Hello示例程序
3.1、SpringMVC——Hello world程序的步骤:
1 先创建一个web模块
2 导入需要的jar包
spring-aop-5.2.5.RELEASE.jar
spring-aspects-5.2.5.RELEASE.jar
spring-beans-5.2.5.RELEASE.jar
spring-context-5.2.5.RELEASE.jar
spring-core-5.2.5.RELEASE.jar
spring-expression-5.2.5.RELEASE.jar
spring-jcl-5.2.5.RELEASE.jar
spring-web-5.2.5.RELEASE.jar
spring-webmvc-5.2.5.RELEASE.jar
3 到web.xml中去配置SpringMVC的前端控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <servlet>
<servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
<servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
|
- 在src源码目录下,创建SpringMVC的容器配置文件 springmvc.xml
1 2 3 4 5 6 7 8 9 10
| <?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 https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com"></context:component-scan>
</beans>
|
5 编写Controller控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Controller public class HelloController {
/** * @RequestMapping 注解用于给请求映射到方法 <br/> * value属性配置方法对象的请求地址(地址唯一) <br/> * / 斜杠在服务器上表示地址为:http://ip:port/工程路径/ <br/> * /hello 表示地址为: http://ip:port/工程路径/hello <br/> * @return */ @RequestMapping(value = "/hello") public String hello(){ System.out.println(" springmvc hello ... "); /** * / 斜杠在服务器上表示地址为:http://ip:port/工程路径/ 映射到代码的web目录 <br/> * 返回值是跳转的路径 , 默认是请求转发 */ return "/pages/ok.jsp"; }
}
|
3.2、SpringMVC的配置文件的另一种存放方式
SpringMVC也有一个Spring容器。也需要配置文件。
它有两种配置方法:
一:是在web.xml中通过给前端控制器 配置init-param实始化参数来进行配置:
1 2 3 4 5 6 7
|
<init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param>
|
二:不需要到web.xml中进行配置,SpringMVC默认会到WEB-INF目录下去加载。
加载的文件名的格式是: (servlet-name的值)-servlet.xml
比如:
1 2
| <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
|
则加载的配置文件名为: dispatcher-servlet.xml
如果servlet-name标签的值是:
1 2
| <servlet-name>abc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
|
则加载的配置文件名为: abc-servlet.xml
4、视图解析器
SpringMVC中有一个组件叫视图解析器。它的作用很直观,将Controller方法中返回的结果转换为视图对象
我们在开发中,有可能需要移动所有文件的位置,这时候有可能就需要到源代码去做批量的修改。
还有可能会更改,视图的具体实现技术。也需要批量到代码中去做批量的修改。
这个时候使用视图解析器可以很好的解决这个问题
有视图解析器之前,我们需要写上完整的跳转路径。
有视图解析器之后,我们只需要写上前缀和后缀之外的内容(文件名)
1 2 3 4 5 6 7
| <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/pages/user/" /> <property name="suffix" value=".jsp" /> </bean>
|
有了视图解析器之后,在Controller中返回的字符串,它会自动的和视图解析器中的前缀和后缀做字符串拼接操作。
然后再进行跳转。
5、@RequestMapping注解详解
@RequestMapping是给个方法配置一个访问地址。就比如web学习的Servlet程序,在web.xml中配置了访问地址之后,它们之间就有一个访问映射关系。
5.1、value属性(重点)
value的作用就是给方法设置一个访问地址,形成映射关系。
1 2 3 4 5 6 7 8
|
@RequestMapping(value = "/hello")
|
就表示此的访问地址为http://ip:port/工程路径/hello 就可以访问此方法。
5.2、params属性
params是要求此请求的参数进行匹配
params=”username” 表示 请求地址必须带有username参数
params=”username=abc” 表示 请求参数中必须要有username,而且值还必须是abc
params=”username!=abc” 表示 1、请求参数中不能有username参数。2、有username参数,但值不能等于abc
params=”!username” 表示 请求地址不能带有username参数
params= {“username!=abc”,”!password”} params可以有多个值,每个值之间是&&关系
以上条件表示要求:
( 请求地址中不能有username参数 || username参数值不能等于 abc && 不能有password参数 )
headers属性在用法上和params属性一样。
只不过他们要求匹配的内容 不一样。
params是要求匹配请求参数
headers要求匹配请求头
1 2 3 4 5 6 7 8 9
|
@RequestMapping(value="/headers",headers = "User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36") public String headers(){ System.out.println(" headers() "); return "ok"; }
|
5.4、method属性(次重点)
method限制匹配请求的方式。
如果不写的请求下。不要求匹配。如果写了,必须严格匹配才允许访问。
1 2 3 4 5 6 7 8 9 10
|
@RequestMapping(value = "/method",method = RequestMethod.POST) public String method(){ System.out.println(" method() called!!! "); return "ok"; }
|
5.5、@RequestMapping标注在Controller类上
@ReqeustMapping如果在类上使用,就给每个方法的请求地址都添加上一个前缀(模块路径)

5.6、通配符在@RequestMapping中的使用(ant模式匹配)
1、绝对匹配
1 2
| @RequestMapping(value = "/params1")
|
2、? 问号 匹配资源路径
? 问号表示一个任意字符,比如匹配fu[0-9a-zA-Z]
1 2 3 4 5 6 7 8 9 10 11
|
@RequestMapping(value = "/fu?") public String fun1(){ System.out.println("fun1() ..."); return "ok"; }
|
3、* 星号 匹配资源路径
* 星号 可以匹配任意个字符
1 2 3 4 5 6 7 8 9 10
|
@RequestMapping(value = "/fu*") public String fun2(){ System.out.println("fun2 () * ..."); return "ok"; }
|
注:当一个路径同时匹配多个规则的时候,调用方法的优先顺序是:
绝对匹配—>>>>?问号匹配—->>>>*星号匹配
一句话总结,就是越精确,越优先
4、? 问号 匹配一个字符的目录
1 2 3 4 5 6 7 8
|
@RequestMapping(value = "/?/fun") public String fun3(){ System.out.println("fun3 () /?/fun ..."); return "ok"; }
|
5、* 星号匹配多个字符的一层目录
1 2 3 4 5 6 7 8
|
@RequestMapping(value = "/*/fun") public String fun4(){ System.out.println("fun4 () /*/fun ..."); return "ok"; }
|
6、** 星星号 匹配多层目录
1 2 3 4 5 6 7 8
|
@RequestMapping(value = "/**/fun") public String fun5(){ System.out.println("fun5 () /**/fun ..."); return "ok"; }
|
源码解析SpringMVC如何调用Controller目标方法:
在浏览器中调访问地址之后。SpringMVC底层是如何访问到的相对应的Controller中的访问的。
Handler就是Controller控制器中用于处理业务的方法。
HandlerAdapter 用来执行 Handler 对应的方法
1 在DispatcherServlet程序中1016行 getHandler() 方法通过 请求的url地址,得到 Controller控制器方法的反射对象
/hello ====>>>> xxxController#xxxx()
/param1 ====>>> xxxxController#xxx()

2 在DispatcherServlet程序中 1023行,getHAndlerAdapter() 获取Handler的适配器对象,适配器对象用于执行Handler

3 在dispatcherServlet程序中 1040行,ha.handle() 方法 通过反射执行Controller#xxx() 目标方法


6、Controller中如何接收请求参数
6.1、原生API参数类型
#### 6.1.1、HttpServletRequest类、HttpSession类,HttpServletResponse类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
@RequestMapping(value = "/param1") public String param1(HttpServletRequest request, HttpSession httpSession, HttpServletResponse httpServletResponse){ System.out.println("reqeust => " + request); System.out.println("请求的url地址:" + request.getRequestURI()); System.out.println("请求的方式:" + request.getMethod()); System.out.println("请求的工程路径:" + request.getContextPath()); System.out.println("======================"); System.out.println(httpSession); System.out.println( "编号:" + httpSession.getId() ); System.out.println("超时时长:" + httpSession.getMaxInactiveInterval()); System.out.println("======================"); System.out.println(httpServletResponse);
return "ok"; }
|
6.2、普通类型入参
1 2 3 4 5 6 7 8 9 10 11
|
@RequestMapping(value = "/param2") public String param2(String username,String password){ System.out.println("username =>" + username); System.out.println("password =>" + password);
return "ok"; }
|
6.3、普通类型数组的参数
要求是客户端发送的参数名和Controller方法中的参数名必须一致!!!
1 2 3 4 5 6 7 8 9 10 11 12
|
@RequestMapping(value = "/param3") public String param3(String[] hobby){
System.out.println("hobby =>" + Arrays.asList(hobby));
return "ok"; }
|
6.4、普通类型使用@RequestParam入参
@RequestParam作用是将客户端的参数赋值给方法的参数
1 2 3 4 5 6 7 8 9 10
|
@RequestMapping(value = "/param4") public String param4(@RequestParam(name = "user",required = false,defaultValue = "我是默认值,我萌萌哒!!!") String username){ System.out.println("username =>" + username); return "ok"; }
|
@RequestHeader 获取指定请求头的值赋给方法参数,用法跟@RequestParam注解一样
1 2 3 4 5 6 7 8
| @RequestMapping(value = "/param5") public String param5( @RequestHeader(name = "User-Agent") String userAgent, @RequestHeader(name = "Accept-Encoding") String acceptEncoding) { System.out.println("请求头UserAgent => " + userAgent); System.out.println("请求头acceptEncoding => " + acceptEncoding); return "ok"; }
|
6.6、@CookieValue获取Cookie值入参
@CookieValue的使用和@ReqeustHeader以及@ReqeustParam一样
1 2 3 4 5 6
| @RequestMapping(value = "/param6") public String param6(@CookieValue(name="JSESSIONID") String jsessionId){ System.out.println(" Cookie的值是 ==>> " + jsessionId); return "ok"; }
|
6.7、一个Pojo对象类型的参数
JavaBean对象
1 2 3 4 5
| public class Person { private Integer id; private Integer age; private String name; private String phone;
|
表单:
1 2 3 4 5 6 7
| <form action="http://localhost:8080/springmvc_01/param7" method="get"> 姓名:<input type="text" name="name"> <br/> 编号:<input type="text" name="ids"> <br/> 年龄:<input type="text" name="age"> <br/> 电话:<input type="text" name="phone"> <br/> <input type="submit" value="提交"> </form>
|
Controller代码:
1 2 3 4 5 6 7 8 9 10
|
@RequestMapping(value = "/param7") public String param7(Person person){ System.out.println(" Person => " + person); return "ok"; }
|
6.8、对象中套对象(级联属性)
JavaBean对象
1 2 3 4 5 6 7 8 9 10 11 12
| public class Car { private String name; private String carNo;
public class Person { private Integer id; private Integer age; private String name; private String phone; private Car car; }
|
表单:
1 2 3 4 5 6 7 8 9 10
| <form action="http://localhost:8080/springmvc_01/param7" method="get"> 姓名:<input type="text" name="name"> <br/> 编号:<input type="text" name="id"> <br/> 年龄:<input type="text" name="age"> <br/> 电话:<input type="text" name="phone"> <br/> <%-- 级联属性写法 --%> 车名:<input type="text" name="car.name"> <br/> 车牌:<input type="text" name="car.carNo"> <br/> <input type="submit" value="提交"> </form>
|
Controller中的代码:
1 2 3 4 5 6 7 8 9 10
|
@RequestMapping(value = "/param7") public String param7(Person person){ System.out.println(" Person => " + person); return "ok"; }
|
7、返回值的设置
7.1、返回String
7.1.1、返回String默认情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @RequestMapping(value = "/return1") public String return1(){ System.out.println(" return1() ");
return "ok"; }
|
7.1.2、显示转发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @RequestMapping(value = "/return2") public String return2(){ System.out.println("return2()");
return "forward:/pages/user/ok.jsp"; }
|
7.1.3、显示重定向
1 2 3 4 5 6 7 8 9 10 11 12 13
| @RequestMapping(value = "/return3") public String return3(){ System.out.println(" return3() 显示重定向 ");
return "redirect:/pages/user/ok.jsp"; }
|
7.2、返回ModelAndView
7.2.1、返回modelAndView的默认情况
1 2 3 4 5 6 7 8 9 10 11 12
| @RequestMapping(value = "/modelAndView1") public ModelAndView modelAndView1(){ ModelAndView modelAndView = new ModelAndView("ok");
System.out.println(" modelAndView1() ");
return modelAndView; }
|
7.2.2、显示转发 和 显示重定向
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @RequestMapping(value = "/forwardAndRedirect") public ModelAndView forwardAndRedirect(){
System.out.println(" modelAndView 中 forwardAndRedirect() ");
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("redirect:/pages/user/ok.jsp"); return modelAndView; }
|
源码解析:目标方法返回值最终都被封装成为ModelAndView
在ReqeustMappingHandlerAdapter类中,第884行, getModelAndView() 方法,将ModelAndViewContainer中的Model和View封装成为ModelAndView返回
