学习目标
第一章-SpringMVC入门
知识点-概述
1. 目标
2. 路径
- 三层架构
- SpringMVC介绍
3. 讲解
3.1 三层架构
服务器端程序,一般都基于两种形式,一种C/S架构程序,一种B/S架构程序. 使用Java语言基本上都是开发B/S架构的程序,B/S架构又分成了三层架构
-
三层架构
表现层:WEB层,用来和客户端进行数据交互的。表现层一般会采用MVC的设计模型
业务层:处理公司具体的业务逻辑的
持久层:用来操作数据库的
-
MVC全名是Model View Controller 模型视图控制器,每个部分各司其职。
Model:数据模型,JavaBean的类,用来进行数据封装。
View:指JSP、HTML用来展示数据给用户
Controller:用来接收用户的请求,整个流程的控制器。用来进行数据校验等(Hibernate Validator)
3.2 SpringMVC
3.2.1 概述
- SpringMVC是一种基于Java的、实现MVC设计模型的、请求驱动类型的(基于HTTP协议)、轻量级Web框架,属于 Spring FrameWork 的后续产品。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。
- SpringMVC已经成为目前最主流的 MVC 框架之一,并且随着Spring3.0的发布,全面超越 Struts2,成为最优秀的 MVC(web层的) 框架。
- 它通过一套注解,让一个简单的Java类成为处理请求的控制器(Controller),而无须实现任何接口(跟Servlet对比)。同时它还支持RESTful编程风格的请求。
3.2.2 SpringMVC的优点
1.清晰的角色划分:
前端控制器(DispatcherServlet)
请求到处理器映射(HandlerMapping) :负责找controller类
处理器适配器(HandlerAdapter) : 负责调用controller类,得到结果,封装结果
视图解析器(ViewResolver) : 负责解析view
处理器或页面控制器(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 编写更容易。
………………还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配
置支持等等。
4. 小结
- Spring MVC 是Spring开发的关于Web层的框架
- 它的作用:接收请求,调用service,响应结果
案例-快速入门【重点】
1.需求
2. 分析
- 创建maven工程,导入依赖
- 创建Controller, 处理的请求
- 创建一个index.jsp页面, success.jsp
- 配置springmvc.xml
- 配置web.xml 启动时加载springmvc.xml 【配置DispatcherServlet】
3. 实现
3.1 导入依赖
<dependencies>
<!--springmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!--jsp-api-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
<!--servlet-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
3.2 编写页面
在webapp里创建
index.jsp
<%--
Created by IntelliJ IDEA.
User: xiaomi
Date: 2021/9/9
Time: 9:06
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h2>这是首页~</h2>
<a href="/sayHi">点我发起请求</a>
</body>
</html>
在webapp里创建
success.jsp
<%--
Created by IntelliJ IDEA.
User: xiaomi
Date: 2021/9/9
Time: 9:06
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h2>这是成功的页面~</h2>
</body>
</html>
3.3 编写Controller
- 在
com.itheima.controller
包中创建类Controller01
- 类上增加
@Controller
注解,声明成为一个bean - 创建
sayHi方法
,并在方法上增加@RequestMapping
注解,声明方法的访问路径
package com.itheima.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/*
入门案例
1. 定义类,类上打注解 @Controller
2. 定义方法, 方法上打注解 @RequestMapping
3. 这个controller能处理 /sayHi的请求,但是要想处理请求,首先必须能抓住请求。
4. 所以要在web.xml配置servlet :: DispatcherServlet
*/
@Controller
public class Controller01 {
@RequestMapping("/sayHi")
public String sayHi(){
System.out.println("调用了Controller01的sayHi方法~!~");
return "/success.jsp";
}
}
3.4 编写配置文件
在
resources
中创建springmvc的配置文件springmvc.xml
, 这个名字可以随意,也可以写成前几天的applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--1. 扫描包-->
<context:component-scan base-package="com.itheima"/>
</beans>
3.5 修改Web.xml
在
webapp/WEB-INF/web.xml
中配置前端控制器DispatcherServlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!--登记|注册 DispatcherServlet,让它来抓请求-->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--1. 告诉DispatcherServlet,springmvc配置文件在哪里。它会解析这个文件,进而去扫描包-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--2. 让DispatcherServlet初始的时机提前到项目发布-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispacher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
3.6 运行测试
- 启动项目,点击首页的超链接访问Controller
sayHi
方法被访问到,并且页面跳转到了success.jsp
4. 小结
- 创建web工程,导入依赖:
spring-webmvc, servlet-api, jsp-api
- 编写Controller
- 提供springmvc.xml:开启组件扫描
- 修改web.xml:配置前端控制器DispatcherServlet
知识点-配置详解
1. 目标
2. 路径
- 原理分析
- springmvc.xml的配置
- web.xml的配置
- controller的配置
3. 讲解
3.1. 原理分析
3.1.1 请求响应流程
3.1.2 三大组件
HandlerMapping
处理器映射器- 作用:根据客户端请求的资源路径,查找匹配的
Controller
及拦截器(类似过滤器)链
- 作用:根据客户端请求的资源路径,查找匹配的
HandlerAdapter
处理器适配器- 作用:用于适配调用不同的
Controller
执行Controller,得到模型和视图
- 作用:用于适配调用不同的
ViewResolver
视图解析器- 作用:用于解析视图,根据视图路径找到真实视图(页面)
3.1.3 详细执行流程
- 客户端发请求到
DispatcherServlet
DispatcherServlet
- 通过
HandlerMapping
处理器映射器,根据请求路径,查找匹配的Controller
及拦截器 - 得到要执行的
Controller
和拦截器(执行链)
- 通过
DispatcherServlet
- 通过
HandlerAdapter
处理器适配器,调用控制器Controller
- 得到
ModelAndView
对象(其中View指视图路径,Model要响应的数据对象)
- 通过
DispatcherServlet
- 通过
ViewResolver
解析视图,得到真实视图(视图路径对应的页面) - 渲染视图(把Model里的数据填充到View里 , 替换页面上的 EL表达式为真实的数据)
- 通过
- 把最终渲染的结果,响应到客户端
3.2. springmvc.xml的配置
跟前几天的
applicationContext.xml
是一样的。只是换了个名字而已。springmvc和spring可以共用同一个配置文件!
3.2.1 基本配置示例
<!--开启组件扫描-->
<context:component-scan base-package="com.itheima.controller"/>
<!--开启mvc的注解驱动-->
<mvc:annotation-driven/>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 静态资源的配置:让SpringMVC不处理静态资源 -->
<mvc:default-servlet-Handler/>
3.2.2 mvc的注解驱动
配置语法
<!--
2. 注解驱动
2.1 标签一定要选择默认是mvc的标签,如果选择到cache的标签,则会出现这个错误:
No bean named 'cacheManager' available
2.2 这个标签会帮助我们在项目里面导入三大组件
2.3 后面用到的一些注解,必须要有这个标签的支撑,否则注解用不了! @ResponseBody
-->
<mvc:annotation-driven/>
配置说明
- 在SpringMVC中,处理器映射器,处理器适配器,视图解析器 被称为三大组件
- 在springmvc.xml中配置
<mvc:annotation-driven/>
标签,可以加载SpringMVC的组件- 如果没有此项配置,SpringMVC也会自动加载组件,所以快速入门中,不配置这一项也可以
- 但是后边课程中,这个标签还有其它作用,所以要配置上
3.2.3 视图解析器设置
1) 视图路径的配置方式
- SpringMVC把页面称为视图,例如JSP|HTML页面就是视图。在
Controller
的方法中,返回的字符串就是跳转的视图(页面)路径 - 视图的路径有两种写法:
- 物理视图:
/success.jsp | success.jsp
,即:视图的真实路径(完整路径)- 直观,但是写起来麻烦
- 例如: 如果有一个页面page.jsp 位于 /webapp/a/b/c/page.jsp , 那么物理视图返回: "/a/b/c/page.jsp";
- 逻辑视图:
success
,需要配合视图解析器,才能得到真实路径- 不直观,但是写起来简单
- 例如: 如果有一个页面page.jsp 位于 /webapp/a/b/c/page.jsp , 那么逻辑视图返回: "page"
- 物理视图:
2) 物理视图的配置方式
- 在
Controller
的方法中,直接返回物理视图路径。 - 不需要配置视图解析器
@Controller
public class Controller01 {
//物理视图跳转: 要写完整的路径地址
@RequestMapping("/sayHi02")
public String sayHi02(){
System.out.println("调用了Controller01的sayHi02方法~!~");
return "/a/b/c/success.jsp";
}
}
3) 逻辑视图的配置方式
- 在
springmvc.xml
中增加以下内容:
<!--
3. 视图解析器
3.1 视图解析器是搭配逻辑视图使用的,它要和方法的返回值拼接起来得到页面的真实路径
前缀 + 方法的返回值 + 后缀 ==== /success.jsp
3.2 视图解析器一旦配置,就会对全局产生影响,所有的controller的方法返回值都要受到它的影响
除了某些方法之外【明天讲!】
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
- 在
Controller
中修改代码,简化方法返回值
@Controller
public class Controller01 {
//逻辑视图跳转:只要写页面的名字即可,需要搭配视图解析器来使用
@RequestMapping("/sayHi03")
public String sayHi03(){
System.out.println("调用了Controller01的sayHi03方法~!~");
return "success";
}
}
- 由视图解析器,帮我们把
prefix + "success" + suffix
,拼接成物理视图/success.jsp
3.2.4 处理静态资源
2.4.1 请求静态资源的说明
-
使用SpringMVC时,客户端访问静态资源时,会访问不到 , 会得到404
-
Tomcat本身具备处理静态资源的能力,但是我们配置的
DispatcherServlet
把Tomcat的默认处理器覆盖掉了;而DispatcherServlet
没有处理静态资源的能力,所以:访问不到静态资源Tomcat里面有一个Servlet,可以处理静态资源: DefaultServlet,它的映射路径是 /
我们使用SpringMVC的时候,在web.xml中,配置DispatcherServlet,配置的地址路径也是 /
2.4.2 两种配置方式解决问题
方案一:指定静态资源的位置
- 针对客户端对静态资源的请求,指定资源所在的位置。让SpringMVC直接去指定目录下加载
- 示例:
<!-- 4. 静态资源处理:
4.1 当我们的DispatcherServlet配置的映射路径是 / 的时候,静态资源就看不到了,报:404的错误
a. 在tomcat里面有一个默认的DefaultServlet, 它的映射路径是 / 它的作用是专门用来处理静态资源
b. 由于DispatcherServlet,映射路径也是 / 所以咱们的DispatcherServlet把DefaultServlet给
覆盖了。而且DispatcherServlet 又不能处理静态资源
4.2 解决静态资源的问题,有两种办法:
a. 配置映射地址和资源路径。
b. 把静态资源的请求,交还给tomcat的DefaultServlet处理
-->
<!--
1. 配置地址和路径的映射
a. 不推荐使用这种办法,因为以后如果还有新的静态资源的类型,那么就需要在这里再增加一行配置
b. 解释:
mvc:resources : 用来做请求地址和资源路径映射
mapping : 请求地址
* : 表示当前的位置,只能匹配一级目录
/html/* ========不能匹配==========localhost:82/html/my.html
/html/* ========不能匹配==========localhost:82/html/a/b/c/my.html
** : 表示匹配任意目录
/html/** ========能匹配==========localhost:82/html/my.html
/html/** ========能匹配==========localhost:82/html/a/b/c/my.html
location : 静态资源所在位置 , 后面要有 / 结尾
-->
<mvc:resources mapping="/html/**" location="/html/"/>
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
方案二:由Tomcat处理静态资源(推荐)
- 如果客户端请求了静态资源,DispatcherServlet处理不了,就交给Tomcat的原生Servlet来处理
- 示例:
<!--2. 把静态资源的处理,交给tomcat的DefaultServlet来做-->
<mvc:default-servlet-handler/>
小结
-
配置视图解析器
- Controller里的方法返回值要写逻辑视图
- 再配置视图解析器
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/"/> <property name="suffix" value=".jsp"/> </bean>
-
如果有静态资源要访问,把静态资源仍然交给Tomcat处理
<mvc:default-servlet-handler/>
-
开启mvc的注解驱动:会注册一些组件,提供一些功能
<mvc:annotation-driven/>
-
开启组件扫描
<context:component-scan base-pcakge="com.itheima.controller"/>
3.3. web.xml的配置
3.3.1 配置示例
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!--登记|注册 DispatcherServlet,让它来抓请求-->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--1. 告诉DispatcherServlet,springmvc配置文件在哪里。它会解析这个文件,进而去扫描包-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--2. 让DispatcherServlet初始的时机提前到项目发布-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--
DispatcherServlet的映射路径应该写什么呢?
1. 映射路径能不能写成 *.do *.itheima 这样的写法呢?【也就是说,只抓尾巴】
a. 可以!并且它不会覆盖掉Tomcat里面的DefaultServlet,也不需要写静态资源处理配置
b. 有一点不好的地方就是:访问所有的controller方法,都必须带上尾巴 .do
2. 映射路径能不能写成 /* 这样的写法呢?
不可以! jsp页面看不到了! 看到的只是jsp页面的源码
a. 在tomcat里面还有一个Servlet叫做:JspServlet, 它专门用来处理jsp页面的请求
b. 这个JspServlet的映射路径是 *.jsp
c. 现在DispatcherServlet,映射的路径是 /* ,那么就会涉及到一个优先级的问题!
d. 映射路径的优先级是这样: /aa > /* > *.jsp | *.do > /
综上所述:
1. 当DispatcherServlet配置的映射路径是 /*的时候,浏览器访问jsp页面这个请求,也会被它抓住
但是DispatcherServlet又不能解析,执行jsp页面,所以直接把这个页面的源码丢给了浏览器!
2. / 表示缺省配置,优先级是最低!所谓的缺省配置就是当没有任何servlet处理这个请求的时候,就由它来处理!
-->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
3.3.2 配置说明
load-on-startup
:配置Servlet的创建时机,值是整数- 如果是正整数,表示服务器一启动就要创建Servlet对象。数值越小,创建的越早
- 如果是0或者负数,表示默认的:第一次访问时,创建Servlet对象
DispatcherServlet
是SpringMVC一切功能的基础和核心,要求:服务器启动时就创建,并且要最早创建,所以设置值为1
init-param
:配置Servlet的初始化参数contextConfigLocation
:配置springmvc.xml的路径,让DispatcherServlet被创建时,加载配置文件,初始化Spring容器
url-pattern
:配置Servlet的路径,通常配置为/
拓展:DispatcherServlet
配置成/
和/*
的区别:
-
对JSP的处理不同。当客户端请求了
xxx.jsp
时 -
如果
DispatcherServlet
配置的是/*
,不能正常访问JSP/*
是目录匹配,优先级高于扩展名匹配(Tomcat里有JspServlet
,路径是*.jsp
)- 必定是由
DispatcherServlet
来处理JSP,但是DispatcherServlet不具备查找和处理jsp的能力,会报错
-
如果
DispatcherServlet
配置的是/
,可以正常访问JSP/
是缺省匹配,优先级低于扩展名匹配(Tomcat里有JspServlet
,路径是*.jsp
)- 必定是由Tomcat来处理JSP,Tomcat本身具备查找和处理JSP的能力,可以正常访问JSP
完全路径匹配 > 目录匹配 > 扩展名匹配 > 缺省匹配
/aa > /* > *.do > /
3.4. controller的配置
3.4.1 配置示例
package com.itheima.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.Servlet;
/*
@Controller :
1. 表示这个类是一个控制器,可以处理请求。
2. spring会把这个类管理起来, 创建这个类的对象。
RequestMapping :
1. 表示方法的映射地址,当什么请求来的时候,会执行这个方法。
2. 属性:
value|path : 用来设置映射路径
method : 用来设置请求方式,表示什么样的请求方式,才能执行这个方法。【默认是都支持!】
RequestMethod.GET : 允许get请求到这里来
RequestMethod.POST : 允许post请求到这里来
如果设置了post,页面还是用get请求过来,那么会报错:
Request method 'GET' not supported
params : 用来要求请求一定要携带指定名称的参数
params="username"`:必须提交了 名称为username的表单参数,才可以访问
params="username=tom"`:必须提交了 名称为username、值为tom的表单参数,才可以访问
params="username!=tom"`:提交了表单参数 名称为username、值不是tom, 才可以访问
3. 这个注解可以打在方法身上,也可以打在类身上!
3.1 在类身上写@RequestMapping,访问方法时,需要加上类上面的映射路径
3.2 这样子做的好处主要是为了和其他的模块进行区分。有前缀的划分。
*/
@Controller
@RequestMapping("/controller01")
public class Controller01 {
@RequestMapping(value = "/sayHi04", method = RequestMethod.GET , params = "username")
public String sayHi04(){
System.out.println("调用了Controller01的sayHi04方法~!~");
return "success";
}
}
3.4.2 配置说明
@RequestMapping
注解 , 通常用在Controller
里,用于设置访问路径
- 注解语法
@RequestMapping(
value="访问路径",
method=请求方式,
params="请求参数"
)
- 常用属性:
- value/path:访问路径,即:什么路径能够访问到这个方法
- method:请求方式,即:什么请求方式能够访问这个方法。从枚举
RequestMethod
中取值RequestMethod.POST
:必须是POST方式,才可以访问到RequestMethod.GET
:必须是GET方式,才可以访问到
- params:请求参数,即:请求携带了什么样的参数能够访问这个方法(了解)
params="username"
:必须提交了 名称为username的表单参数,才可以访问params="username=tom"
:必须提交了 名称为username、值为tom的表单参数,才可以访问params="username!=tom"
:提交了表单参数 名称为username、值不是tom, 才可以访问
- 如果注解用在Controller类上
- 表示设置访问路径的一级目录,要和方法上的路径组装成访问路径。用于模块化管理,例如:
- 类上有注解
@RequestMapping("/user")
- 类里方法上有注解
@RequestMapping("/save")
- 那么方法的访问路径是:
/user/save
- 类上有注解
- 表示设置访问路径的一级目录,要和方法上的路径组装成访问路径。用于模块化管理,例如:
第二章-获取请求数据【重点】
知识点-请求参数的绑定
1.目标
2.路径
- 绑定机制
- 支持的数据类型
- 使用要求
3.讲解
-
绑定机制
表单提交的数据都是key=value格式的(username=zs&password=123), SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的(要求:提交表单的name和方法的参数的名称是相同的)
<form action="">
用户名:<input type="text" name="username"/>
密码: <input type= "password" name="password"/>
<input type="submit"/>
</form>
public String register(String username , String password){
}
//======================================================
class User{
private String username;
private String password;
}
public String register02(User user){
}
-
支持的数据类型
基本数据类型和字符串类型
实体类型(JavaBean)
集合数据类型(List、map集合等)
-
使用要求
-
如果是基本类型或者 String 类型: 要求我们的参数名称必须和controller中方法的形参名称保持一致。 (严格区分大小写) .
-
如果是 对象 类型,或者它的关联对象: 要求表单中参数名称和对象类的属性名称保持一致
-
如果是集合类型,有两种方式:
- 第一种:要求集合类型的请求参数必须在对象类 中。在表单中请求参数名称要和 对象类中集合属性名称相同。给 List 集合中的元素赋值, 使用下标【】。给 Map 集合中的元素赋值, 使用键值对。
- 第二种:接收的请求参数是 json 格式数据。需要借助一个注解实现 @RequestBody
-
4.小结
- 绑定机制
SpringMVC的参数绑定过程是把表单提交的请求参数,作为controller里面方法的参数进行绑定的。
- 支持的数据类型 :
基本数据类型和字符串类型
实体类型(JavaBean)
集合数据类型(List、map集合等)
- 使用要求: 名字需要一样
知识点-获取请求参数
1.目标
2.路径
- 基本类型和String
- 对象类型
- 数组
- 对象包含属性
3.讲解
3.1 基本类型和String 【重点】
-
说明
- 客户端提交的表单参数名称, 和Controller里方法参数名称相同
- SpringMVC会自动绑定同名参数,并自动转换类型
-
页面
-
index.jsp
<h2>提交简单的参数:</h2>
<form action="/requestSimpleParam" method="post">
用户名:<input type="text" name="username"/><br/>
密 码:<input type="text" name="password"/><br/>
年 龄:<input type="text" name="age"/><br/>
<input type="submit"/>
</form>
- success.jsp
<%--
Created by IntelliJ IDEA.
User: xiaomi
Date: 2021/9/29
Time: 11:10
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h2>这是成功的页面~!~</h2>
</body>
</html>
- controller
package com.itheima.controller;
import com.itheima.bean.*;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
@Controller
public class Controller01 {
/*
获取简单的参数:
要求:
1. 方法的参数名字必须和页面的form表单中的name属性的值 一样!
用户名:<input type="text" name="username"/>
*/
@RequestMapping("/requestSimpleParam")
public String requestSimpleParam(String username, String password , int age){
System.out.println("username = " + username);
System.out.println("password = " + password);
System.out.println("age = " + age);
return "success";
}
}
3.2 对象类型 【重点】
SpringMVC会帮我们自动把表单参数,封装成对象,但是要求:
- 客户端提交的表单参数名称,必须和JavaBean的属性名一样!
- Pojo(User)
package com.itheima.bean;
import lombok.Data;
@Data
public class User {
private String username;
private String password;
private int age;
}
- 前端页面
<h2>提交对象的参数:</h2>
<form action="/requestObjectParam">
用户名:<input type="text" name="username"/><br/>
密 码:<input type="text" name="password"/><br/>
年 龄:<input type="text" name="age"/><br/>
<input type="submit"/>
</form>
- controller
package com.itheima.controller;
import com.itheima.bean.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
@Controller
public class Controller01 {
/*
获取对象参数:
要求:
1. 页面提交上来的form表单的name属性值必须和JavaBean的属性名字一样!
用户名:<input type="text" name="username"/>
public class User {
private String username;
}
*/
@RequestMapping("/requestObjectParam")
public String requestObjectParam(User user){
System.out.println("user = " + user);
return "success";
}
}
3.3 数组【了解】
注:只能2接前端多个参数(一个名字对应多个值),不能用List集合。确实需要List集合接收时,使用包装user.list
- 页面
<h2>提交数组的参数:</h2>
<form action="/requestArrayParam">
请选择您的爱好:<br/>
<input type="checkbox" name="hobby" value="smoke"/>抽烟
<input type="checkbox" name="hobby" value="drink"/>喝酒
<input type="checkbox" name="hobby" value="firehead"/>烫头<br/>
<input type="submit"/>
</form>
- Controller01
package com.itheima.controller;
import com.itheima.bean.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
@Controller
public class Controller01 {
/*
获取数组参数:
要求:
1. 页面上的表单项,name属性值必须一样!
2. 方法参数的名字必须和name属性的值一样!
*/
@RequestMapping("/requestArrayParam")
public String requestArrayParam(String [] hobby){
System.out.println("hobby=" + Arrays.toString(hobby));
return "success";
}
}
3.4 对象包含集合【了解】
3.4.1 对象中包含对象
- 对象
@Data
public class Address {
private String province;
private String city;
}
//---------------------------------------------
@Data
public class Account {
private String username;
private int money;
private Address address;
}
- 页面
<h2>提交对象包含对象的参数:</h2>
<form action="/requestObjectInObject">
用户名:<input type="text" name="username"/><br/>
金 额:<input type="text" name="money"/><br/>
省 份:<input type="text" name="address.province"/><br/>
城 市:<input type="text" name="address.city"/><br/>
<input type="submit"/>
</form>
- Controller01
package com.itheima.controller;
import com.itheima.bean.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
@Controller
public class Controller01 {
/*
获取对象包含对象的参数:
要求:
1. 如果是普通的数据,那么页面的name属性值就写 类里面的普通属性名
用户名:<input type="text" name="username"/><br/>
2. 如果对象属性,那么页面的name属性值就写 对象属性.内部的子属性
省 份:<input type="text" name="address.province"/><br/>
*/
@RequestMapping("/requestObjectInObject")
public String requestObjectInObject(Account account){
System.out.println("account = " + account);
return "success";
}
}
3.4.2 对象中包含List
- 对象
@Data
public class Account02 {
private String name;
private int money;
}
//-----------------------------------------------------------
@Data
public class User02 {
private String username;
private String password;
//表示一个用户有多个账户
private List<Account02> account02List;
}
- 前端页面
<h2>提交对象包含List的参数:</h2>
<form action="/requestListInObject">
用户名:<input type="text" name="username"/><br/>
密 码:<input type="text" name="password"/><br/>
第一个账户的名称:<input type="text" name="account02List[0].name"/><br/>
第一个账户的金额:<input type="text" name="account02List[0].money"/><br/>
第二个账户的名称:<input type="text" name="account02List[1].name"/><br/>
第二个账户的金额:<input type="text" name="account02List[1].money"/><br/>
<input type="submit"/>
</form>
- Controller01.java
package com.itheima.controller;
import com.itheima.bean.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
@Controller
public class Controller01 {
/*
获取对象包含集合List:
要求:
页面上的name属性的值,要写集合属性[下标].子属性
第一个账户的名称:<input type="text" name="account02List[0].name"/><br/>
第一个账户的金额:<input type="text" name="account02List[0].money"/><br/>
*/
@RequestMapping("/requestListInObject")
public String requestListInObject(User02 user02){
System.out.println("user02 = " + user02);
return "success";
}
}
3.4.3 对象中包含Map
- 对象
@Data
public class Account03 {
private String name;
private int money;
}
//--------------------------------------------------------
@Data
public class User03 {
private String username;
private String password;
//表示一个用户有多个账户
private Map<String , Account03> account03Map;
}
- 页面
<h2>提交对象包含Map的参数:</h2>
<form action="/requestMapInObject">
用户名:<input type="text" name="username"/><br/>
密 码:<input type="text" name="password"/><br/>
第一个账户的名称:<input type="text" name="account03Map['abc'].name"/><br/>
第一个账户的金额:<input type="text" name="account03Map['abc'].money"/><br/>
第二个账户的名称:<input type="text" name="account03Map['abc2'].name"/><br/>
第二个账户的金额:<input type="text" name="account03Map['abc2'].money"/><br/>
<input type="submit"/>
</form>
- Controller01.java
package com.itheima.controller;
import com.itheima.bean.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
@Controller
public class Controller01 {
/*
获取对象包含集合Map:
要求:
页面上的name属性的值,要写成 集合属性['KEY'].子属性
第一个账户的名称:<input type="text" name="account03Map['abc'].name"/><br/>
第一个账户的金额:<input type="text" name="account03Map['abc'].money"/><br/>
*/
@RequestMapping("/requestMapInObject")
public String requestMapInObject(User03 user03){
System.out.println("user03 = " + user03);
return "success";
}
}
4.小结
-
请求参数类型是简单(基本,String)类型
- 方法的形参和请求参数的name一致就可以
-
请求参数类型是pojo对象类型
- 形参就写pojo对象
- pojo的属性必须和请求参数的name一致就可以
-
请求参数类型是pojo对象类型, 包含集合
- 形参就写pojo对象
- pojo的属性必须和请求参数的name一致就可以
- 如果包含对象, 页面的name属性=对象属性名.自己属性
- 如果包含List, 页面上的name属性=list的属性名[下标].pojo属性名
- 如果包含map, 面上的name属性=map的属性名['key'].pojo属性名
-
提交数组,只能用数组接收,多个参数的name属性名一致,参数要与controller中的参数名一致。
不能直接提交List与map集合, 需要通过其它方式转换(fastjson)
知识点-细节处理和特殊情况
1.目标
2.路径
- 请求参数乱码处理
- 自定义类型转换器
- 使用 ServletAPI 对象作为方法参数
3.讲解
3.1 请求参数乱码
如果请求参数或者响应中有中文就会乱码。在web阶段,我们通过一个自定义的过滤器实现了统一乱码解决
req.setCharacterEncoding("utf-8")
resp.setContentType("text/html;charset=utf-8");
现在SpringMVC本身 ,也给我们提供了一个过滤器
CharacterEncodingFilter
,用于解决乱码问题 。 只有在post请求才会有中文乱码,如果tomcat > 8.5的版本,那么tomcat已经帮助修复了get请求的中文乱码。如果使用了tomcat7的插件来跑项目, get请求还是会有乱码的!需要配置一下下!
- 在web.xml里面配置编码过滤器
<!--配置字符编码过滤器-->
<filter>
<filter-name>char</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--指定使用UTF-8的编码 , encoding是固定写法-->
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>char</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- 如果使用了tomcat7的插件,get请求会出现中文乱码,那么可以这么解决
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<!-- 指定端口 -->
<port>82</port>
<!-- 请求路径 -->
<path>/</path>
<!--配置编码-->
<uriEncoding>utf-8</uriEncoding>
</configuration>
</plugin>
</plugins>
</build>
3.2 自定义类型转换器
默认情况下,SpringMVC已经实现一些数据类型自动转换。 内置转换器全都在:
org.springframework.core.convert.support
包下 ,如遇特殊类型转换要求,需要我们自己编写自定义类型转换器。
3.2.1 场景
- 页面
<h2>提交包含日期的参数:</h2>
<form action="/requestDateParam">
用户名:<input type="text" name="username"/><br/>
密 码:<input type="text" name="password"/><br/>
出生日期:<input type="text" name="birthday"/><br/>
<input type="submit"/>
</form>
- User04
package com.itheima.bean;
import lombok.Data;
import java.util.Date;
@Data
public class User04 {
private String username;
private String password;
private Date birthday;
}
- Controller01.java
package com.itheima.controller;
import com.itheima.bean.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
@Controller
public class Controller01 {
/*
获取日期格式的数据
*/
@RequestMapping("/requestDateParam")
public String requestDateParam(User04 user04){
System.out.println("user04 = " + user04);
return "success";
}
}
- 报错了:
3.2.2 自定义类型转换器
步骤:
- 创建一个类实现Converter 接口
- 配置类型转换器
实现:
-
定义一个类,实现 Converter 接口
该接口有两个泛型,S:表示接受的类型, T:表示目标类型(需要转的类型)
package com.itheima.converter;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/*
自定义日期格式转换器
1. 定义类,实现接口Converter
里面有两个泛型: S : 表示的是源数据的类型 , T: 表示的是目标数据的类型
2. 实现方法convert
*/
public class DateConverter implements Converter<String , Date> {
/**
*
* @param source 从页面接收到的数据
* @return 转化出来的日期对象。
*/
public Date convert(String source) {
try {
System.out.println("来到我们的日期转化器了:" + source);
//1. 定义SimpleDateFormat对象
SimpleDateFormat sf =null ;
if(source .contains("-")){
sf = new SimpleDateFormat("yyyy-MM-dd");
}else if(source.contains("/")){
sf = new SimpleDateFormat("yyyy/MM/dd");
}
//2. 转化
return sf.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
-
在springmvc.xml里面配置转换器
spring 配置类型转换器的机制是,将自定义的转换器注册到类型转换服务中去
<!--2. 注解驱动-->
<mvc:annotation-driven conversion-service="cs"/>
<!--
5. 配置日期格式转换器
5.1 配置转换工厂对象
5.2 给它里面的集合 converters 注入我们自己的类型转换器!
-->
<bean id="cs" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<bean class="com.itheima.converter.DateConverter"/>
</property>
</bean>
3.3 使用原始Servlet的API
3.3.1 说明
- 在Controller的方法中,可以使用Servlet的原始API,只要在方法中直接定义参数即可,SpringMVC框架会提供对应的实参
- SpringMVC支持的Servlet原始API有:
- HttpServletRequest :代表HTTP请求
- HttpServletResponse :代表HTTP响应
- HttpSession :代表会话
- java.security.Principal :Java的授权认证接口,当前已认证的用户
- Locale :当前请求的语言环境
- InputStream :请求体的字节流对象
- OutputStream :响应体的字节流对象
- Reader :请求体的字符流对象
- Writer:响应体的字符流对象
示例
- index.jsp
<h2>使用Servlet API来获取参数:</h2>
<form action="/getParamFromServletAPI" method="post">
用户名:<input type="text" name="username"/><br/>
密 码:<input type="text" name="password"/><br/>
年 龄:<input type="text" name="age"/><br/>
<input type="submit"/>
</form>
- success.jsp
<%--
Created by IntelliJ IDEA.
User: xiaomi
Date: 2021/9/29
Time: 11:10
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h2>这是成功的页面~!~${username}</h2>
</body>
</html>
- Controller01.java
package com.itheima.controller;
import com.itheima.bean.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
@Controller
public class Controller01 {
/*
使用原始的ServletAPI来获取参数
*/
@RequestMapping("/getParamFromServletAPI")
public void getParamFromServletAPI(HttpServletRequest req , HttpServletResponse resp , HttpSession session) throws IOException {
//1. 获取参数
String username = req.getParameter("username");
String password = req.getParameter("password");
int age = Integer.parseInt(req.getParameter("age"));
System.out.println("username = " + username);
System.out.println("password = " + password);
System.out.println("age = " + age);
//2. 把数据保存到session作用域
session.setAttribute("username", username);
//3. 跳转页面
resp.sendRedirect("/success.jsp");
}
}
4.小结
-
处理post乱码 直接在web.xml 配置编码过滤器 characterEncodingFilter 过滤地址是: /*
-
类型转换器,
- 创建一个类实现Converter <src, target>
- 在springmvc.xml进行配置 conversionService
- springmvc默认使用的日期格式yyyy/MM/dd
-
ServletApi方式
-
直接方法的形参里面绑定request(获取ip,获取项目路径), response(下载文件). session...
-
使用属性注入
@Autowired private HttpServletRequest req
-
总结
springmvc的入门:
它是什么?
它是spring框架的后续产品,作用于web层,它是一个轻量级的web层框架,
能够接受、处理客户端发送过来的请求。
它怎么用?
1. 定义Controller类,类上打注解 @Controller
2. 定义方法 , 方法上打注解@RequestMapping
3. 写springmvc.xml配置文件
a. 扫描包
<context:componenet-scan base-package="com.itheima"/>
b. 注解驱动
<mvc:annotation-driven/>
c. 视图解析器
<bean class="InternalResourceViewResolver">
<property name="preffix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
d. 静态资源处理
<mvc:default-servlet-handler/>
4. 在web.xml中配置DispatcherServlet
获取参数:
1. 绑定机制:
a. 要求参数名字 或者 类中的属性名字 必须和页面上的name属性的值一样!
2. 参数类型:
a. 简单参数
b. 对象参数
c. 数组
d. 对象包含对象
e. 对象包含集合(List&Map)
细节和类型转化器:
1. 中文乱码问题
GET : tomcat > 8.5 不用管, tomcat7, 需要设置一行 <uriEncoding>utf-8</uriEncoding>
POST: 配置过滤器
2. 日期格式的问题
默认情况下,spring里面内置了日期格式的转化,不过它只支持 / 的日期,如果想匹配 - 的日期
需要自定义类型转换器。