H5W3
当前位置:H5W3 > 其他技术问题 > 正文

2020:0613 — SpringMVC(一)

今日内容

    第1章 SpringMVC的基本概念
第2章 SpringMVC的入门
第3章 请求参数的绑定
第4章 常用注解
 

第1章 SpringMVC的基本概念

1.1 三层架构和MVC

    1. 我们开发服务器端程序,一般都基于两种形式,一种C/S架构程序,一种B/S架构程序。
2. 使用Java语言基本上都是开发B/S架构的程序,B/S架构又分成了三层架构。
3. 三层架构
1. 表现层:WEB层,用来和客户端进行数据交互的。表现层一般会采用MVC的设计模型
2. 业务层:处理公司具体的业务逻辑的
3. 持久层:用来操作数据库的
 

1.2 MVC模型

    MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,
是一种用于设计创建 Web 应用程序表现层的模式。MVC中每个部分各司其职:
1. Model(模型): 通常指的就是我们的数据模型。作用一般情况下用于封装数据。
2. View(视图): 通常指的就是我们的jsp或者html。作用一般就是展示数据的。
通常视图是依据模型数据创建的。
3.Controller(控制器):用来接收用户的请求,整个流程的控制器。用来进行数据校验等。
 

1.3 SpringMVC概述

    SpringMVC是一种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于 Spring
FrameWork 的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序
的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用 Spring 的 Spring MVC 框架或集成其他MVC开发框架,如Struts1(现在一般不用),Struts2等。
SpringMVC已经成为目前最主流的MVC框架之一,并且随着Spring3.0的发布,全面超越Struts2,
成为最优秀的 MVC 框架。
它通过一套注解,让一个简单的Java类成为处理请求的控制器,而无须实现任何接口。同时它
还支持RESTful编程风格的请求。
SpringMVC 在三成框架的位置:
 

1.4 SpringMVC概的优势

    1、清晰的角色划分:
前端控制器(DispatcherServlet)
请求到处理器映射(HandlerMapping)
处理器适配器(HandlerAdapter)
视图解析器(ViewResolver)
处理器或页面控制器(Controller)
验证器( Validator)
命令对象(Command 请求参数绑定到的对象就叫命令对象)
表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。
2、分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要。
3、由于命令对象就是一个POJO,无需继承框架特定API,可以使用命令对象直接作为业务对象。
4、和Spring 其他框架无缝集成,是其它Web框架所不具备的。
5、可适配,通过HandlerAdapter可以支持任意的类作为处理器。
6、可定制性,HandlerMapping、ViewResolver等能够非常简单的定制。
7、功能强大的数据验证、格式化、绑定机制。
8、利用Spring提供的Mock对象能够非常简单的进行Web层单元测试。
9、本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。
10、强大的JSP标签库,使JSP编写更容易。
......
 

1.5 SpringMVC和Struts2的优略分析

1.共同点:
它们都是表现层框架,都是基于MVC模型编写的。
它们的底层都离不开原始ServletAPI。
它们处理请求的机制都是一个核心控制器。
2.区别:
Spring MVC 的入口是 Servlet, 而 Struts2 是 Filter
Spring MVC 是基于方法设计的,而Struts2是基于类,Struts2每次执行都会创建一个动作类。
所以Spring MVC 会稍微比 Struts2 快些。
Spring MVC 使用更加简洁,同时还支持 JSR303, 处理 ajax 的请求更方便
(JSR303 是一套JavaBean参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这
些注解加在我们JavaBean的属性上面,就可以在需要校验的时候进行校验了。)
Struts2 的OGNL 表达式使页面的开发效率相比Spring MVC更高些,但执行效率并没有比JSTL
并没有比JSTL提升,尤其是struts2的表单标签,远没有html执行效率高。
 

第2章 SpringMVC的入门案例

2.1 案例需求

2.1 环境搭建

1.创建一个MavenWeb项目:
步骤1:
 
    步骤2:
注意:
无论在< groupId> 还是< artifactId>中的命名都只能是数字字母下划线,括号,汉字和空格都不能出现!
 
    步骤3:构建完成
在点击finish完成构建之前,这里有个小点可以注意一下:
Maven会默认的到网上去下载一些插件,这个下载的过程很浪费时间。我们通过
添加一对键值对来解决这个问题:
archetypeCatalog --- internal
 
2.补全Maven的目录结构
 
3.导入依赖坐标--修改pom.xml文件
1. 修改编译版本
 
    2.锁定Spring版本(抽取版本信息)
 
    3.导入依赖坐标
```
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
```
4.配置一个前端控制器
这个前端控制器就是一个servlet,在web.xml中配置:
```
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
```
一个最基本的前端控制器:
```
<servlet>
<!--自己起一个名字-->
<servlet-name>dispatcherServlet</servlet-name>
<!--这个类是spring提供好的,固定写法-->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<!--让servlet被请求到-->
<servlet-mapping>
<!--名称要和上面一致-->
<servlet-name>dispatcherServlet</servlet-name>
<!--拦截的路径:/表示拦截所有-->
<url-pattern>/</url-pattern>
</servlet-mapping>
```
5. 创建一个spring配置文件
 

2.2 部署服务器

2.3 完善spring配置文件

1.引入名称空间
```
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"              //IOC的bean管理
xmlns:mvc="http://www.springframework.org/schema/mvc"               //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">
```
2.开启扫描注解
```
<context:component-scan base-package="cn.itcast"></context:component-scan>
```
3.把控制器类交给IOC
```
@Controller                     //把这个类交给IOC容器
public class HelloController {
public String sayHello(){
System.out.println("hello,springmvc");
return null;
}
}
```
 

2.4 加载spring的配置文件

    1.spring配置文件没有加载的话,扫描:
<context:component-scan base-package="cn.itcast"></context:component-scan>
显然也就不能生效,那在控制器类上假的注解@Controller 不也没什么效果吗?
2.我们要让Spring的配置文件加载,那么什么时候加载呢?
在web.xml的前端控制器中去加载,让servlet(配置的前端控制器)去加载spring这个配置文件。
3. 提供一个全局的初始化参数:<init-param/>
* contextConfigLocation:classpath:springmvc.xml:
告知servlet初始加载spring配置文件。
* servlet这个配置的前端控制器,正常来讲什么时候创建?
原来是第一次发请求的时候才创建servlet对象,现在启动服务器就创建这个前端控制器。
<load-on-startup>1</load-on-startup>:
意思是启动服务器就去创建<servlet-class/>标签体中的servlet对象:
org.springframework.web.servlet.DispatcherServlet
```
<servlet>
<servlet-name>dispatcherServlet</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>
<!--启动服务器就去创建这个servlet对象-->
<load-on-startup>1</load-on-startup>
</servlet>
```
4. 所以整个配置下来就是:
服务器一打开就去创建servlet对象dispatcherServlet(前端控制器),然后
前端控制器加载spring.xml配置文件。spring.xml配置文件中的扫描开始生效。
<context:component-scan base-package="cn.itcast"></context:component-scan>
然后这个类就被扫到,变成对象放到IOC容器中。
```
@Controller                     //把这个类交给IOC容器
public class HelloController {
public String sayHello(){
System.out.println("hello,springmvc");
return null;
}
}
```
 

2.5 请求映射:拦截请求执行方法。

    ```
<body>
<h3>入门程序</h3>
<a href="https://juejin.im/post/5ee4738e6fb9a047cf334185/hello">入门程序</a>
</body>
```
我们点击页面上的超链接,然后想让 public class HelloController 类中的 sayHello()方法
执行。
我们就需要在方法在加一个注解:@RequestMapping(path = {"https://juejin.im/hello"})
@RequestMapping:请求的一个映射。前台发送的请求映射上的话,就拦截下来,执行方法。
@RequestMapping(path = {"https://juejin.im/hello"}) :满足/hello这个路径的请求的话,就执行方法。
```
@Controller     //把这个类交给IOC容器
public class HelloController {
@RequestMapping(path = {"https://juejin.im/hello"})
public String sayHello(){
System.out.println("hello,springmvc");
return null;
}
}
```
 

2.6 跳转页面

    请求成功后,希望跳转到一个成功的页面,怎么跳呢?
```
@Controller     //把这个类交给IOC容器
public class HelloController {
@RequestMapping(path = {"https://juejin.im/hello"})
public String sayHello(){
System.out.println("hello,springmvc");
return "success";
}
}
```
SpringMVC框架里面有一个默认的规则:
返回一个success,这个其实可以默认表示当前这个JSP文件的名字。所以我们就要
提供一个success.jsp文件。
 
    最后一步:
怎么找到这个文件呢?
 

2.7 在spring.xml中配置一个:视图解析器

        InternalResourceViewResolver
```
<!--视图解析器对象-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
```
同时在里面配置参数:
1. prefix:表示文件所在的目录。
<property name="prefix" value="/WEB-INF/pages/"></property>
跳转时,视图解析器会找这个目录下某文件
2. suffix:表示文件的后缀名是什么。
<property name="suffix" value=".jsp"></property>
那么页面想跳转时,底层就会用这个视图解析器帮你跳转到指定的页面。
 

2.8 开启springMVC开启注解的支持

        当前案例用不到,以后要用。
<mvc:annotation-driven></mvc:annotation-driven>
 

2.9 注意一下路径问题

    1.项目名是:day_0613_springmvc01
项目根路径是:http://localhost:8080/day_0613_springmvc01/
 
        <a href="https://juejin.im/post/5ee4738e6fb9a047cf334185/hello"> :
那么发送的请求从当前项目根目录下开始:http://localhost:8080/day_0613_springmvc01/hello
<a href="https://juejin.im/hello"> :
发送的请求:http://localhost:8080/hello
a标签:<a href="https://juejin.im/day53/index.jsp">跳转</a> 的路径如果是"/"开头,
"/"则相当于"localhost:8080"。
 
    2.项目名是:空
项目根路径是:http://localhost:8080/
 
        <a href="https://juejin.im/post/5ee4738e6fb9a047cf334185/hello"> :
那么发送的请求从当前项目根目录下开始:http://localhost:8080/hello
<a href="https://juejin.im/hello"> :
发送的请求:http://localhost:8080/hello
 
    3.总结:
首先我们都是在tomcat上部署的,项目在tomcat的webapps目录下:
 
        注意观察:
我们的源码项目名是:day_0613_springmvc01_quickstart
我们部署的项目名:day_0613_springmvc01
所以在webapps目录下,就生成了一个day_0613_springmvc01项目。
 
            我们的当前项目部署的根路径就是:
http://localhost:8080/day_0613_springmvc01/
 

第3章 入门程序的分析

3.1 启动服务器,加载一些配置文件:

    1 web.xml
```
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>dispatcherServlet</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>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
```
1.1 DispatcherServlet前端控制器被创建
1.2 前端控制器加载pring配置文件:springmvc.xml
springmvc.xml :
```
<?xml version="1.0" encoding="UTF-8"?>
<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="cn.itcast"></context:component-scan>
<!--视图解析器对象-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--下面需要开启springMVC开启注解的支持-->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
```
1.2.1 springmvc中开启了注解扫描:
<context:component-scan base-package="cn.itcast"></context:component-scan>
```
@Controller
public class HelloController {
@RequestMapping(path = "https://juejin.im/hello")
public String sayHello(){
System.out.println("hello,springmvc");
return "success";
}
}
```
1.2.1.1 将HelloController这个类变成了bean对象(默认单例)放到IOC容器中。
1.2.2 springmvc中配置了视图解析器
```
<!--视图解析器对象-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
```
bean标签:说明也变成对象放到了IOC容器中。将来就可以调用它,
来帮我们完成跳转页面的功能。
1.2.3 springMVC开启注解的支持
```
<mvc:annotation-driven></mvc:annotation-driven>
```
那么SpringMVC中的注解可以使用了:
```
@Controller
public class HelloController {
@RequestMapping(path = "https://juejin.im/hello")
public String sayHello(){
System.out.println("hello,springmvc");
return "success";
}
}
```
@RequestMapping(path = "https://juejin.im/hello")也可以生效了
这么一下来,将来谁发送http请求后,如果请求路径满足 @RequestMapping(path = "https://juejin.im/hello")。
然后HelloController这个对象中的方法sayHello()就会执行。
启动服务器,加载一些配置文件后,该创建的对象就创建了,该生效的注解就生效了。
这就是启动服务器后做的一些事情。
 

3.2 发送请求,后台处理请求

    1.发送请求:
```
<body>
<h3>入门程序</h3>
<a href="https://juejin.im/post/5ee4738e6fb9a047cf334185/hello">入门程序</a>
</body>
```
发送的路径就是:项目名称/hello
http://localhost:8080/day_0613_springmvc01/hello
2.发送的请求会先被web.xml中配置的前端控制器拦截到
```
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
```
这里配置的是拦截所有。
3. 然后会根据注解:@RequestMapping(path = "https://juejin.im/hello")
```
@Controller
public class HelloController {
@RequestMapping(path = "https://juejin.im/hello")
public String sayHello(){
System.out.println("hello,springmvc");
return "success";
}
}
```
找到了HelloController类中的sayHello方法并执行
4. sayHello方法执行完毕后,会返回一个"success"字符串给前端控制器servlet
5. springmvc中还配置了一个:视图解析器对象InternalResourceViewResolver
```
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
```
6. 前端控制器就会去找视图解析器这个对象InternalResourceViewResolver
根据视图解析器InternalResourceViewResolver的配置:
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
到/WEB-INF/pages/目录下找后缀名是.jsp的文件。
然后解析返回值"success"是一个success.jsp文件,发现/WEB-INF/pages/目录下有
对应的文件
7. 前端控制器就成功跳转到success.jsp页面,响应给客户端。客户端就看到了最终的结果
 
整个过程中前端控制器是非常重要的
 

第4章 springmvc框架基于组件方式的执行流程

4.1 执行的流程

springmvc框架它是基于组件的方式,执行整个的流程。
 

4.1 入门案例中涉及的组件

1、DispatcherServlet:前端控制器
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由
它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。
2、HandlerMapping:处理器映射器
HandlerMapping负责根据用户请求找到Handler即处理器,SpringMVC提供了不同的映射器实现不同的
映射方式,例如:配置文件方式,实现接口方式,注解方式等。
3、 Handler:处理器 --- 在本案例是Controller类中的sayHello方法
```
@Controller
public class HelloController {
@RequestMapping(path = "https://juejin.im/hello")
public String sayHello(){
System.out.println("hello,springmvc");
return "success";
}
}
```
它就是我们开发中要编写的具体业务控制器,由DispatcherServlet把用户请求转发到Handler。
由Handler对具体的用户请求进行处理。
4、 HandlAdapter:处理器适配器
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多
类型的处理器进行执行。
 
5、View Resolver:视图解析器
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理
视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给
用户。
6、 View:视图
SpringMVC框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。
我们最常用的视图就是jsp。
一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根
据业务需求开发具体的页面。
7、 <mvc:annotation-driven>说明
在SpringMVC的各个组件中,处理器映射器、处理器适配器、视图解析器称为SpringMVC的三大组件。
但是我们却没有在配置文件中配置处理器映射器、处理器适配器组件。
注意:
我们在springmvc.xml中配置了:
<mvc:annotation-driven></mvc:annotation-driven>开启了mvc注解支持。
相当于默认加载了处理器映射器、处理器适配器。
即在springmvc.xml配置了<mvc:annotation-driven></mvc:annotation-driven>,相当于
替代了注解处理器和适配器的配置。
注意:
一般开发中,我们都需要写上此标签。虽然从入门案例中看,我们不写也行,随着课程的深入,
该标签还有具体的使用场景。
 

第5章 springmvc中的注解

5.1 @RequestMapping(path =””)

    1.作用:
用于建立请求URL和处理请求方法之间的对应关系。
2.位置:方法,类,接口
* 类上:
请求URL的第一级访问目录,此处不写的话,就相当于应用的根目录。写的话需要以/开头。
它的出现是为了是我们的URL可以按照模块化管理。
例如账户模块:
```
/account/add
/account/update
/account/delete
```
```
@Controller
@@RequestMapping(path="/account")
public class HelloController {
@RequestMapping(path = "/add")
public String sayHello(){
...
}
@RequestMapping(path = "/update")
public String sayHello(){
...
}
@RequestMapping(path = "/delete")
public String sayHello(){
...
}
}
```
那么JSP页面请求路径时:
<a href="https://juejin.im/post/5ee4738e6fb9a047cf334185/account/add ">RequestMapping注解</a>
<a href="https://juejin.im/post/5ee4738e6fb9a047cf334185/account/update  ">RequestMapping注解</a>
<a href="https://juejin.im/post/5ee4738e6fb9a047cf334185/account/delete ">RequestMapping注解</a>
例如订单模块:
```
/order/add
/order/update
/order/delete
```
```
@Controller
@@RequestMapping(path="/order")
public class HelloController {
@RequestMapping(path = "/add")
public String sayHello(){
...
}
@RequestMapping(path = "/update")
public String sayHello(){
...
}
@RequestMapping(path = "/delete")
public String sayHello(){
...
}
}
```
那么JSP页面请求路径时:
<a href="https://juejin.im/post/5ee4738e6fb9a047cf334185/order/add ">RequestMapping注解</a>
<a href="https://juejin.im/post/5ee4738e6fb9a047cf334185/order/update  ">RequestMapping注解</a>
<a href="https://juejin.im/post/5ee4738e6fb9a047cf334185/order/delete ">RequestMapping注解</a>
* 方法上:
请求URL的第二级访问目录
3.属性:
1.value:用于指定请求的URL,和path互为别名。
2.path:用于请求的URL,和value互为别名
3.method:用于指定接收请求的方式:get/post
```
RequestMethod[] method() default {};
public enum RequestMethod {
GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
}
```
是一个枚举类。
@RequestMapping(path = "https://juejin.im/hello", method={RequestMethod.POST})
3.2  测试一下:发送的URL请求默认是GET方式
 
            我们设置的方法只能接受POST请求,所以这里回报405错误。
4. params:用于指定限制请求参数的条件,它支持简单的表达式。要求
* 请求参数的key和value必须和配置的一模一样。
```
@RequestMapping(path = "https://juejin.im/hello", params={"username"})
public String sayHello(){
System.out.println("hello,springmvc");
return "success";
}
```
* 要求发送过来的请求URL必须有参数username
```
<a href="https://juejin.im/post/5ee4738e6fb9a047cf334185/user/hello">RequestMapping注解</a>
```
* 如果没有参数就发送请求,那么回报400错误:Bad Request
 
            * 想要能正常访问:的请求URL必须有参数username
```
<a href="https://juejin.im/post/5ee4738e6fb9a047cf334185/user/hello?username=%E5%91%B1%E5%91%B1">RequestMapping注解</a>
```
* 如果还指定的参数值,那么请求参数值也必须一样。
@RequestMapping(path = "https://juejin.im/hello", params={"username=heihei"})
<a href="https://juejin.im/post/5ee4738e6fb9a047cf334185/user/hello?username=heihei">RequestMapping注解</a>
* 小结:要求请求参数的key和value必须和配置的一模一样。
params = {"moeny!100"},表示请求参数中money不能是100。
5. headers:用于指定限制请求消息头的条件。
发送的请求中必须包含的请求头。
* 演示一下
```
@RequestMapping(path = "https://juejin.im/hello", params={"username"}, headers = {"Accept"})
```
 

第6章 请求参数的绑定。

6.1 绑定的机制

    我们都知道请求参数都是基于key=value的。
SpringMVC绑定请求参数的过程就是通过把表单提交请求中的参数,传递给控制器@Controller中
的方法中的参数里。前提要是参数名一致。
例如:
<a href="https://juejin.im/post/5ee4738e6fb9a047cf334185/account/findAccount?accountId=10">查询账户</a>
请求参数是:accountId=10
```
@RequestMapping("/findAccount")
public String findAccount(Integer accountId) {
System.out.println("查询了账户。。。。"+accountId);
return "success";
}
```
 

6.2 支持的数据类型

    基本类型参数:
包括基本类型和String类型
POJO类型参数:
包括实体类,以及关联的实体类
数组和集合类型参数:
包括List结构和Map结构的集合(包括数组)
1.演示:基本类型
```
@Controller
@RequestMapping("/param")
public class ParamController {
@RequestMapping("/testParam")
public String testParam(String username, String password){
System.out.println("执行了...");
return "success";
}
}
```
```
<a href="https://juejin.im/post/5ee4738e6fb9a047cf334185/param/testParam?username=hehe&password=1234">请求参数绑定</a>
```
思考:如果请求参数有许多,那么在控制器的方法中(处理器)岂不是要写很多的参数
我们考虑用表单提交参数,然后将参数封装到javaBean中。
2.演示:表单提交参数,然后将参数封装---bean实体类
* param.jsp:提交一个表单
将表单中的参数封装到JavaBean中,要求表单中的name和JavaBean的属性名相同。
去找set方法封装。
```
<form action="param/testParamBean" method="post" >
姓名:<input type="text" name="username"/><br>
密码:<input type="text" name="password"/><br>
金额:<input type="text" name="money"/><br>
<input type="submit" value="提交"/><br>
</form>
```
* JavaBean
```
public class Account implements Serializable {
private String username;
private String password;
private Double money;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
```
}
}
```
* Controller:控制器类
```
@Controller
@RequestMapping("/param")
public class ParamController {
@RequestMapping("/testParamBean")
public String testParamBean(Account account){
System.out.println("测试参数绑定:javabean");
System.out.println(account);
return "success";
}
}
```
会自动的将提交大参数封装到JavaBean类Account中,注意表单中的name属性要和实体类
中的属性一致。
3.演示:表单提交参数,然后将参数封装---bean实体类且有引用类型属性
* JavaBean :Account
```
private String username;
private String password;
private Double money;
private User user;
```
* JavaBean:User
```
private String uName;
private Integer age;
```
* param.jsp:提交一个表单
```
<form action="param/testParamBean" method="post" >
<%--将表单中的参数封装到JavaBean中,要求表单中的name和JavaBean的属性名相同。去找set方法封装--%>
姓名:<input type="text" name="username"/><br>
密码:<input type="text" name="password"/><br>
金额:<input type="text" name="money"/><br>
用户的姓名:<input type="text" name="user.uName"/><br>
用户的年龄:<input type="text" name="user.age"/><br>
<input type="submit" value="提交"/><br>
</form>
```
* Controller:控制器类
```
@RequestMapping("/testParamBean")
public String testParamBean(Account account){
System.out.println("测试参数绑定:javabean");
System.out.println(account);
return "success";
}
```
4.演示:表单提交参数,然后将参数封装---bean实体类,有引用类型属性和集合类型属性
* JavaBean :Account
```
private String username;
private String password;
private Double money;
private User user;
private List<User> userList;
private Map<String, User> userMap;
```
* param.jsp:提交一个表单
 
        * Controller:控制器类
 

6.3 MVC框架自动的帮你进行了数据类型的转换

    页面提交到后台的任何数据都是以字符串类型提交的,但是当后台的数据类型是其他时,比如Integer。
后台拿到全部的数据后,也成功将数据封装到对应的JavaBean中。
即MVC框架在后台,自动的帮你进行了数据类型的转换。
基本上常用的数据类型都帮你自动转了。
但是也有特殊情况:
2000/11/11  可以自动转成对应的日期。
 
    2000-11-11  就无法转成对应的日期。
 
    解决:自定义类型转换器
 
6.3.1 自定义类型转换器
    第一步:定义一个类,实现Converter接口,该接口有两个泛型
String ---> Date
注意导包:
 
    ```
public class StringToDateConverter implements Converter<String, Date> {
/**
*
* @param source 传入进来的字符串
* @return
*/
@Override
public Date convert(String source) {
//1.判断
if(source == null){
throw new RuntimeException("请您传入数据");
}
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
try {
//2.把字符串转成日期
return df.parse(source);
} catch (Exception e) {
throw new RuntimeException("数据类型转换出现错误");
}
}
}
```
第二步:在spring配置文件中配置类型转换器。
spring配置类型转换器的机制是,将自定义的转换器注册到类型转换服务中去。
酱紫定义的类型转换添加进类型转换服务中,不是覆盖(添加不是覆盖)。
```
<!--配置自定义类型转换器-->
<bean id="conversionServiceFactoryBean"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<!--将你写的自定义类型转换器注册到:类型转换服务中-->
<property name="converters">
<set>
<bean class="cn.itcast.utils.StringToDateConverter"></bean>
</set>
</property>
</bean>
<!--下面需要开启springMVC开启注解的支持-->
<mvc:annotation-driven conversion-service="conversionServiceFactoryBean"></mvc:annotation-driven>
```
分析一下上面的配置:
1.配置类型转换器工厂:
<bean id="conversionServiceFactoryBean"
class="org.springframework.context.support.ConversionServiceFactoryBean">
</bean>
2.将你写的自定义类型转换器注册到:类型转换服务
```
<bean id="conversionServiceFactoryBean"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<!--将你写的自定义类型转换器注册到:类型转换服务中-->
<property name="converters">
<set>
<bean class="cn.itcast.utils.StringToDateConverter"></bean>
</set>
</property>
</bean>
```
3.开启类型转换服务
<mvc:annotation-driven conversion-service="conversionServiceFactoryBean"></mvc:annotation-driven>
注意:
因为<mvc:annotation-driven/>默认开启了处理器映射器、处理器适配器,但是没有加载类型转换服务,
所以我们要在<mvc:annotation-driven/>标签中开启。
4.配置成功
 

6.4 解决POST请求中文乱码问题。

* POST发送请求时,会出现乱码问题:
 
* GET发送请求时,不会出现乱码问题:
 
* 解决POST请求中文乱码问题 :
在web.xml中配置一个过滤器,拦截所有请求,然后设置编码为UTF-8
```
<!--
配置过滤器解决中文乱码:
<url-pattern>/*</url-pattern> :能拦截所有的请求
-->
<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>
```
 

6.5 使用Servlet原生的API对象作为方法参数

    拿到Request/Response/Session/ServletContext
* param.jsp
```
<a href="https://juejin.im/post/5ee4738e6fb9a047cf334185/param/testServletAPI">Servlet原生的API</a>
```
* 控制器类
```
/**
* Servlet原生API获取
* @return
*/
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request, HttpServletResponse response){
System.out.println("测试ServletAPI");
System.out.println("request:   "+request);
System.out.println("response:   "+response);
HttpSession session = request.getSession();
System.out.println("session:   "+session);
ServletContext servletContext = session.getServletContext();
System.out.println("servletContext:    "+servletContext);
return "success";
}
```
* 得到原生API对象
 

第7章 常用注解

7.1 RequestParam

    作用:
把请求中指定名称的参数给控制器中的形参赋值
属性:
value:请求中参数中的名称
required:请求参数中是否必须提供此参数。默认值:true。
表示必须提供,如果不提供将报错。
一般是请求参数名和后台实体类中的属性名不一致时,用此注解。
 
    用法:
注意:required没有配置,默认值是true。
注解@RequestParam(name="name")后,请求参数必须是name,此时再username也会错。
 

7.2 RequestBody

作用:
用于获取请求体内容。直接使用得到的是key=value&key=value...结构的数据。
get请求方法不适用:
get方式是没有请求体的,它将请求参数都放到了地址栏上。
post才存在请求体。
所以不能发用超链接发送请求,应该用表单发送请求。
属性:
required:是否必须有请求体。默认值是:true。当取值为true时,get请求方式会报错。
如果取值为false,个体请求得到的是null。
用法:
 

7.3 PathVariable

作用:
用于绑定URL中的占位符。例如:请求url中 /delete/{id},这个{id}就是URL占位符
URL支持占位符是spring3.0之后加入的。是springmvc支持rest风格URL的一个重要标志。
属性:
value:用于指定URL中占位符名称。
required:是否必须提供占位符。
REST风格URL:
请求地址都一样,根据不同的请求方式最终让不同的方法去执行。
如果请求方法也一样,根据占位符来匹配。
 
用法:
 

7.4 RequestHeader

作用:
用于获取请求消息头。
属性:
value:提供消息头名称
required:是否必须有此消息头。
住:在实际开发中一般不怎么用
 

7.5 CookieValue

作用:
用于把指定cookie名称的值传入控制器方法参数
属性:
value:指定cookie的名称
required:是否必须有此cookie
用法:
 

7.6 ModelAttribute

作用:
该注解是SpringMVC4.3版本以后新加入的,它可以用于修饰方法和参数
出现在方法上,表示当前方法会在控制器的方法执行之前先之前。它可以修饰没有返回值的方法,
也可以修饰有具体返回值的方法。
出现在参数上,获取指定的数据给参数赋值。
验证一下: 出现在方法上,表示当前方法会在控制器的方法执行之前先之前。
 
属性:
value:用于获取数据数据的key。key可以是POJO的属性名称,也可以是map结构的key。
应用场景:
实体类由三个属性。
表单只提交了两个属性,原来会被封装成null。
现在希望剩下的属性使用数据库原来的数据。
原来的情况:
 
用法1:ModelAttribute注解的方法可以把返回的结果,传给后面前端控制器要执行的方法中的参数。
 
用法2:ModelAttribute注解的方法,将查询的结果存入一个map中。
前端控制器要执行的方法再从map中取数据。
 

7.7 SessionAttributes

作用:
用于多次执行控制器方法间的参数共享。
SessionAttributes注解只能作用在类上:将数据存入session中
属性:
value:用于指定存入的属性名称
type:用于指定存入的数据类型
用法:
1.  JSP页面发送请求:
```
<a href="https://juejin.im/post/5ee4738e6fb9a047cf334185/anno/testSessionAttributes/">SessionAttributes</a><br>
```
2. Controller类:SessionAttributes注解只能作用在类上:将msg=丑丑哒存入到session对象中
```
@Controller
@RequestMapping("/anno")
@SessionAttributes(value = {"msg"})
public class AnnoController {
@RequestMapping("/testSessionAttributes")
public String testSessionAttributes(Model model){
System.out.println("testSessionAttributes:  执行了");
//这里:底层会存储到Request域对象中
model.addAttribute("msg", "丑丑哒");
//然后在success.jsp页面,取出来
return "success";
}
}
```
分析一下:
当根据请求的URL走到testSessionAttributes()方法时,方法里面有一个参数Model model
我们在model参数里面设置数据:"msg", "丑丑哒" 。这里底层会将数据存储到Request域对象中。
然后在类声明上标注@SessionAttributes(value = {"msg"}) :将msg=丑丑哒存入到session对象中
然后在success.jsp页面显示出来
3. success.jsp
 
4. 显示在页面
 
取出刚才存入到session中的值,再清空Session。
 

本文地址:H5W3 » 2020:0613 — SpringMVC(一)

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址