SpringMVC
概述
SpringMVC是一种基于Java的、实现MVC设计模型的、请求驱动类型的(基于HTTP协议)、轻量级Web框架,属于 Spring FrameWork 的后续产品。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。
SpringMVC已经成为目前最主流的 MVC 框架之一,并且随着Spring3.0的发布,全面超越 Struts2,成为最优秀的 MVC(web层的) 框架。
它通过一套注解,让一个简单的Java类成为处理请求的控制器,而无须实现任何接口(跟Servlet对比)。同时它还支持RESTful编程风格的请求。
优点
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 编写更容易。 ………………还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配 置支持等等。
快速入门
导入依赖
<dependencies> <!--springmvc--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!--servlet-api--> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.1</version> <scope>provided</scope> </dependency> <!--jsp-api--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> </dependencies>
编写页面
在webapp里创建
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>成功</title> </head> <body> <h1>成功页面</h1> </body> </html>
编写Controller
在
com.zml.controller
包中创建类Controller
类上增加
@Controller
注解,声明成为一个bean创建
sayHi方法
,并在方法上增加@RequestMapping
注解,声明方法的访问路径import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class Controller { @RequestMapping("/sayHi") public String sayHi(){ System.out.println("执行了sayHi方法~~~"); //返回页面的名字,包含后缀名 return "success.jsp"; } }
编写配置文件
在
resources
中创建springmvc的配置文件springmvc.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"> <!--开启组件扫描--> <context:component-scan base-package="com.zml"/> </beans>
修改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> <!-- 引入springmvc的配置文件 1. 配置初始化参数,这个初始化参数DispatcherServlet会读取它的。 2. 读取到它了之后,就可以解析springmvc.xml 进而能够去帮助我们创建三层架构里面的类对象 Controller Service Dao param-name: contextConfigLocation 是固定的,表示配置文件的路径 param-value: 配置文件的位置,需要使用claspath:打头,后面跟着文件名,表示在类路径下面。 --> <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> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <!--这里映射的规则要写成 / 不要写成 /*, 否则jsp页面无法处理,无法显示--> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
首页
<html> <head> <title>Title</title> </head> <body> <a href="sayHi">访问SayHi方法</a><br/> </body> </html>
配置详解
三大组件
HandlerMapping
处理器映射器
作用:根据客户端请求的资源路径,查找匹配的
Controller
及拦截器(类似过滤器)链
HandlerAdapter
处理器适配器
作用:用于适配调用不同的
Controller
执行Controller,得到模型和视图
ViewResolver
视图解析器
作用:用于解析视图,根据视图路径找到真实视图(页面)
详细执行流程
客户端发请求到
DispatcherServlet
DispatcherServlet
通过
HandlerMapping
处理器映射器,根据请求路径,查找匹配的Controller
及拦截器得到要执行的
Controller
和拦截器(执行链)
DispatcherServlet
通过
HandlerAdapter
处理器适配器,调用控制器Controller
得到
ModelAndView
对象(其中View指视图路径,Model要响应的数据对象)
DispatcherServlet
通过
ViewResolver
解析视图,得到真实视图(视图路径对应的页面)渲染视图(把Model里的数据填充到View里)
把最终渲染的结果,响应到客户端
springmvc.xml的配置
基本配置示例
<!--开启组件扫描--> <context:component-scan base-package="com.zml.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/>
配置说明
在SpringMVC中,处理器映射器,处理器适配器,视图解析器 被称为三大组件
在springmvc.xml中配置
<mvc:annotation-driven/>
标签,可以加载SpringMVC的组件
如果没有此项配置,SpringMVC也会自动加载组件,所以快速入门中,不配置这一项也可以
但是后边课程中,这个标签还有其它作用,所以要配置上
视图解析器设置
视图路径的配置方式
SpringMVC把显示层的内容(页面)称为视图,例如JSP|HTML页面就是视图。在
Controller
的方法中,返回的字符串就是跳转的视图路径视图的路径有两种写法:
物理视图:
/success.jsp
,即:视图的真实路径(完整路径)
直观,但是写起来麻烦
逻辑视图:
success
,需要配合视图解析器,才能得到真实路径
不直观,但是写起来简单
处理静态资源
使用SpringMVC时,客户端访问静态资源时,会访问不到
Tomcat本身具备处理静态资源的能力,但是我们配置的
DispatcherServlet
把Tomcat的默认处理器覆盖掉了;而DispatcherServlet
没有处理静态资源的能力,所以:访问不到静态资源方案一:指定静态资源的位置
针对客户端对静态资源的请求,指定资源所在的位置。让SpringMVC直接去指定目录下加载
示例:
<!-- mapping:客户端请求的路径 location:资源所在的位置 --> <mvc:resources mapping="/js/**" location="/js/"/> <mvc:resources mapping="/img/**" location="/img/"/> <mvc:resources mapping="/css/**" location="/css/"/>
方案二:由Tomcat处理静态资源(推荐)
如果客户端请求了静态资源,DispatcherServlet 处理不了,就交给Tomcat的原生Servlet来处理
示例
<mvc:default-servlet-handler/>
web.xml的配置
配置示例
<!--配置SpringMVC的前端控制器--> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--配置springmvc.xml路径--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <!--服务器启动时,就创建DispatcherServlet对象--> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <!--把前端控制器设置为 默认的处理器(覆盖Tomcat的默认处理器)--> <url-pattern>/</url-pattern> </servlet-mapping>
配置说明
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
controller的配置
配置示例
@Controller//必须声明成bean对象 @RequestMapping("/controller02") public class Controller02 { @RequestMapping("/demo") public String demo(){ System.out.println("demo......"); return "success"; } }
配置说明
@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
使用示例
package com.zml.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller //表示这个类是一个控制器,主要是用来处理请求的。 @RequestMapping("/user") public class UserController { //访问地址: localhost:8080/项目映射名/user/add //@RequestMapping("/add") //只有get请求方式才能访问它 //@RequestMapping(value = "/add",method = RequestMethod.GET) //只有post请求方式才能访问它 //限定请求方式,无非是有几个理由: // 1. get请求和post请求取值不同,担心来请求的时候使用的方式不对,直接限定只服务post请求 // 2. 尽量的形成一种规范, RestFull API风格。 @RequestMapping(value = "/add",method = RequestMethod.POST) public String add(){ System.out.println("user..add.."); return "success02"; } @RequestMapping("/delete") public String delete(){ System.out.println("user..delete.."); return "success02"; } @RequestMapping("/update") public String update(){ System.out.println("user..delete.."); return "success02"; } @RequestMapping("/findAll") public String findAll(){ System.out.println("user..findAll.."); return "success02"; } }
获取请求数据
请求参数的绑定
绑定机制
表单提交的数据都是key=value格式的(username=zs&password=123), SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的(要求:提交表单的name和参数的名称是相同的)
支持的数据类型
基本数据类型和字符串类型
实体类型(JavaBean)
集合数据类型(List、map集合等)
使用要求
如果是基本类型或者 String 类型: 要求我们的参数名称必须和controller中方法的形参名称保持一致。 (严格区分大小写) .
如果是 对象 类型,或者它的关联对象: 要求表单中参数名称和 POJO 类的属性名称保持一致。并且controller中方法的参数类型是 POJO 类型 .
如果是集合类型,有两种方式:
第一种:要求集合类型的请求参数必须在 POJO 中。在表单中请求参数名称要和 POJO 中集合属性名称相同。给 List 集合中的元素赋值, 使用下标。给 Map 集合中的元素赋值, 使用键值对。2
第二种:接收的请求参数是 json 格式数据。需要借助一个注解实现 @RequestBody
获取请求参数
基本类型和String
客户端提交的表单参数名称, 和Controller里方法参数名称相同
SpringMVC会自动绑定同名参数,并自动转换类型
示例
页面
<html> <head> <title>Title</title> </head> <body> <h2>提交简单的参数</h2> <form action="controller01/simple"> 用户名: <input type="text" name="username"/><br/> 密 码: <input type="text" name="password"/><br/> <input type="submit"/> </form> </body> </html>
controller
@Controller public class Controller01 { /** * 获取简单的参数,基本数据类型以及字符串的数据 * 要求:页面的参数的名字(name属性的值)必须和方法的形参名字一样才可以。 * @param username * @param password * @return */ @RequestMapping("/controller01/simple") public String getSimpleParam(String username , String password){ System.out.println(username + "=" + password); // /打头的页面路径,会从项目映射名后面开始拼接。 return "/success.jsp"; } }
对象类型
SpringMVC会帮我们自动把表单参数,封装成POJO对象,但是要求:
客户端提交的表单参数名称,必须等于JavaBean的属性名
示例
Pojo(Account和Address)
@Data public class Address { private String province; private String city; } @Data public class Account { private int id; private String name; private double money; //采用Address类来封装地址信息 private Address address; }
前端页面
<h2>提交对象的参数</h2> <form action="controller01/object"> <%--页面上的名字必须要和对象的属性名一样--%> 账户名: <input type="text" name="name"/><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>
controller
/** * 获取对象数据,把参数封装成一个对象 * 要求: * 1. 页面提交过来的参数名必须和对象里面的属性名一样,才能接收。 * 2. 页面如果给过来的东西有点多,但是属性有点少,也没事,不会报错。 * 3. 页面给过来的东西有点少,但是属性有点多,也没事,不会报错。 * @param account * @return */ @RequestMapping("/controller01/object") public String getObjectParam(Account account){ System.out.println("account=" + account); // /打头的页面路径,会从项目映射名后面开始拼接。 return "/success.jsp"; }
数组
注:只能用数组来接前端多个参数,不能用List集合。确实需要List集合接收时,使用包装user.list
示例
页面
<hr/> <h2>提交数组的参数</h2> <form action="controller01/array"> 爱好: <input type="checkbox" name="hobby" value="唱"> 唱 <input type="checkbox" name="hobby" value="跳"> 跳 <input type="checkbox" name="hobby" value="rap"> rap <input type="submit"/> </form>
controller
/** * 获取数组的参数,传递过来的是一个key对应多个值,希望它包装到数组里面去。 * 数组的名字需要和页面上的名字一样,否则SpringMVC不知道怎么赋值 * @param hobby * @return */ @RequestMapping("/controller01/array") public String getArrayParam(String [] hobby){ System.out.println("hobby=" + Arrays.toString(hobby)); return "/success.jsp"; }
对象包含集合
对象
@Data public class User { private String username; private String password; private int age ; //一个用户里面有很多的账户。 private List<Account> accountList; }
页面
<hr/> <h2>提交对象包含List的参数</h2> <form action="controller01/objectlist"> 用户名: <input type="text" name="username"/><br/> 密 码: <input type="text" name="password"/><br/> 年 龄: <input type="text" name="age"/><br/> <%--如果要把这份数据填充到集合属性(属性是一个list)里面 ,那么需要配合使用[]下标的写法--%> 第一个账户的名称: <input type="text" name="accountList[0].name"/><br/> 第一个账户的金额: <input type="text" name="accountList[0].money"/><br/> 第二个账户的名称: <input type="text" name="accountList[1].name"/><br/> 第二个账户的金额: <input type="text" name="accountList[1].money"/><br/> <input type="submit"/> </form>
controller
/** * 对象当中含有集合List的参数获取。 想要分装到集合里面的数据,需要用到[]下标 跟上属性来赋值。 * 第一个账户的名称: <input type="text" name="accountList[0].name"/><br/> * @param user * @return */ @RequestMapping("/controller01/objectlist") public String getObjectListParam(User user){ System.out.println("user=" + user); return "/success.jsp"; }
POJO 类中包含Map
对象
@Data public class User02 { private String username; private String password; private int age ; //一个用户里面有很多的账户。 private Map<String , Account> accountMap; }
页面
<hr/> <h2>提交对象包含Map的参数</h2> <form action="controller01/objectmap" method="post"> 用户名: <input type="text" name="username"/><br/> 密 码: <input type="text" name="password"/><br/> 年 龄: <input type="text" name="age"/><br/> <!--如果要把这份数据填充到集合属性(属性是一个list)里面 ,那么需要配合使用[]下标的写法 aa ,bb 是map中的key --> 第一个账户的名称: <input type="text" name="accountMap['aa'].name"/><br/> 第一个账户的金额: <input type="text" name="accountMap['aa'].money"/><br/> 第二个账户的名称: <input type="text" name="accountMap['bb'].name"/><br/> 第二个账户的金额: <input type="text" name="accountMap['bb'].money"/><br/> <input type="submit"/> </form>
controller
/** * 对象当中含有集合Map的参数获取。 想要分装到集合里面的数据,需要用到[]下标 跟上属性来赋值。 * 第一个账户的名称: <input type="text" name="accountList[0].name"/><br/> * @param user * @return */ @RequestMapping("/controller01/objectmap") public String getObjectMapParam(User02 user){ System.out.println("user=" + user); return "/success.jsp"; }
细节处理和特殊情况
请求参数乱码
如果请求参数或者响应中有中文就会乱码。在web阶段,我们通过一个自定义的过滤器实现了统一乱码解决
现在SpringMVC本身 ,也给我们提供了一个过滤器
CharacterEncodingFilter
,用于解决乱码问题
在web.xml里面配置编码过滤器
<!--配置中文编码过滤器--> <filter> <filter-name>char</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <!--需要给定一个参数,这个参数的名字是固定的,不能改变,必须是encoding 值:一般就给utf-8即可--> <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>
自定义类型转换器
默认情况下,SpringMVC已经实现一些数据类型自动转换。 内置转换器全都在:
org.springframework.core.convert.support
包下 ,如遇特殊类型转换要求,需要我们自己编写自定义类型转换器。例如Date
定义一个类,实现 Converter 接口
该接口有两个泛型,S:表示接受的类型, T:表示目标类型(需要转的类型)
/** * 创建自己的日期转换器 * 泛型的解释: * 第一个泛型就是:源数据的类型 String * 第二个泛型就是:目标数据的类型 Date */ public class DateConvertor implements Converter<String, Date> { /** * 转换方法 * @param s 源数据,就是页面给过来的字符串1999-10-10 * @return 目标对象 Date对象 */ public Date convert(String s) { try { //1. 创建simpledateformat SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); //2. 把字符串转化成日期对象返回即可 return simpleDateFormat.parse(s); } catch (ParseException e) { e.printStackTrace(); } return null; } }
在springmvc.xml里面配置转换器
spring 配置类型转换器的机制是,将自定义的转换器注册到类型转换服务中去
在 annotation-driven 标签中引用配置的类型转换服务
<!-- 配置的类型转换服务--> <mvc:annotation-driven conversion-service="cs"/> <!-- 注册日期转换器 ConversionServiceFactoryBean : 是用来注册转化器的 converters : 属性,是一个set集合,可以注册很多的转换器 在里面指定我们自己的转换器bean对象 --> <bean id="cs" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.zml.convertor.DateConvertor"/> </set> </property> </bean>
页面
<h2>提交含有日期的数据</h2> <form action="controller01/register" method="post"> 用户名:<input type="text" name="username"/><br/> 密 码:<input type="text" name="password"/><br/> 生 日:<input type="date" name="birthday"/><br/> <input type="submit"/> </form>
对象
@Data public class User { private String username; private String password; private Date birthday; }
controller
@Controller public class Controller01 { /** * 为了演示:获取的数据里面含有日期的数据。 * @param user * @return */ @RequestMapping("/controller01/register") public String register(User user){ System.out.println("user=" + user); return "/success.jsp"; } }
使用原始Servlet的API
在Controller的方法中,可以使用Servlet的原始API,只要在方法中直接定义参数即可,SpringMVC框架会提供对应的实参
SpringMVC支持的Servlet原始API有:
HttpServletRequest :代表HTTP请求
HttpServletResponse :代表HTTP响应
HttpSession :代表会话
java.security.Principal :Java的授权认证接口,当前已认证的用户
Locale :当前请求的语言环境
InputStream :请求体的字节流对象
OutputStream :响应体的字节流对象
Reader :请求体的字符流对象
Writer:响应体的字符流对象
示例
页面
<a href="/controller02/demo?username=zs">使用 ServletAPI 对象作为方法参数</a>
controller
import com.zml.bean.User; 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; /* 使用Servlet的API */ @Controller public class Controller02 { @RequestMapping("/controller02/demo") public String demo(HttpServletRequest request , HttpServletResponse response , HttpSession session){ System.out.println("request=" + request); String username = request.getParameter("username"); System.out.println("username=" + username); System.out.println("response=" + response); System.out.println("session=" + session); return "/success.jsp"; } }
常用的注解
@RequestParam
作用:
把请求中指定名称的参数给控制器中的形参赋值。
属性
value: 请求参数中的名称。 required:请求参数中是否必须提供此参数。 默认值: true。表示必须提供,如果不提供将报错。
defaultValue:默认值
使用场景:
form提交,url参数使用的是?方式来提交请求
Request.getParameter
使用示例
页面
<a href="user/testRequestParam?name=张三">测试RequestParam </a>
controller
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/testRequestParam") public String testRequestParam(@RequestParam(value = "name",required = true,defaultValue = "李四") String username){ System.out.println("username="+username); return "success"; } }
@RequestParam 只能用于接收 url 的传参 ?name=xxx, form表单的提交。使用list来接收数组类型
无法接收提交的json数据(contentType=application/json)
@RequestBody
作用
用于获取请求体内容。 直接使用得到是 key=value&key=value...结构的字符串。
把获得json类型的数据转成pojo对象(后面再讲)【推荐】
注意: get 请求方式不适用。
属性
required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值为 false, get 请求得到是 null。
@RequestBody 不能使用get请求, 在Controller的方法参数里,有且只有一个
Request.getInputStream()
使用示例
页面
<hr/> <h3>测试ReqeuestBody</h3> <form action="user/testRequestBody " method="post"> 用户名:<input type="text" name="username"/><br/> 密码:<input type="password" name="password"/><br/> <input type="submit" value="测试RequestBody"/> </form>
controller
@RequestMapping("testRequestBody") public String testRequestBody(@RequestBody String queryStr){ System.out.println("queryStr="+queryStr); return "success"; }
接收json数据
客户端发Ajax请求,提交json格式的数据
服务端接收json格式的数据,直接封装成User对象
使用示例
pom.xml中添加jackson的依赖:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.6</version> </dependency>
springmvc.xml中,增加配置静态资源的处理
<!--配置静态资源的处理--> <mvc:default-servlet-handler/>
页面
<input type="button" value="Ajax提交json" onclick="submitJson()"> <script src="${pageContext.request.contextPath}/js/axios-0.18.0.js"></script> <script> function submitJson() { var data = { name:"jack", age:20 }; axios.post("${pageContext.request.contextPath}/other/body2",data); } </script>
controller
@RequestMapping("/body2") public String body2(@RequestBody User user){ System.out.println(user); return "success"; }
@PathVariable
作用:
用于绑定 url 中的占位符。 例如:请求 url 中 /delete/{id}, 这个{id}就是 url 占位符。 url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。
属性:
value: 用于指定 url 中占位符名称。 required:是否必须提供占位符。
场景:获取路径中的参数,与restful编程风格一起,通常微服架构中使用
Request.getRequestURI,通过字符串截取
使用示例
页面
<a href="user/testPathVaribale/1">测试PathVaribale</a><br/>
controller
@RequestMapping("testPathVaribale/{id}") public String testPathVaribale(@PathVariable(value = "id") Integer id){ System.out.println("id="+id); return "success"; }
@RequestHeader
作用: 用于获取请求消息头。
属性: value:提供消息头名称 required:是否必须有此消息头
从请求头中获取参数,鉴权(token 畅购open auth 2.0 jwt token) Authorization
Request.getHeader()
使用示例
页面
<a href="user/testRequestHeader">测试RequestHeader</a><br/>
controller
@RequestMapping("testRequestHeader") public String testRequestHeader(@RequestHeader(value = "User-Agent") String requestHeader){ System.out.println("requestHeader="+requestHeader); return "success"; }
@CookieValue
作用:
用于把指定 cookie 名称的值传入控制器方法参数。
属性:
value:指定 cookie 的名称。 required:是否必须有此 cookie。
框架封闭才会用到,如:获取用户浏览记录
使用示例
页面
<a href="user/testCookieValue">测试CookieValue</a><br/>
controller
@RequestMapping("testCookieValue") public String testCookieValue(@CookieValue(value="JSESSIONID") String sessionId){ System.out.println("sessionId="+sessionId); return "success"; }
响应数据和视图
返回页面视图
controller方法返回的字符串会被解析成页面视图(即:页面的地址路径)
返回逻辑视图名称
方法返回的字符串,和视图解析器里的前缀、后缀拼接得到真实路径,再进行跳转
是请求转发跳转
返回带前缀的物理视图
请求转发:
forward:/success.jsp
重定向:
redirect:/success.jsp
注意:如果带有
forward
或者redirect
,那么路径必须是真实路径使用示例
@Controller public class Controller01 { /* 物理视图返回: 直接写完页面的路径名字 路径可以有 / 也可以没有 / 有 / :表示是绝对路径写法 ,拼接的地址,是从项目名后面开始拼接的。 没有 / :表示相对路径写法,相对的是controller方法的路径 */ @RequestMapping("/page01") public String page(){ return "/success.jsp"; } /* 使用视图解析器的逻辑视图 1. 不需要写完完整的路径,只写页面的名字即可 2. 需要配置视图解析器,配置前缀和后缀 3. 视图解析器一旦配置,即影响全局的逻辑视图 4. 如下面的方法返回值所示: 它的返回值是一个success, 那么会和我们配置的前缀和后缀拼接到一起,形成一个完整的路径。 */ @RequestMapping("/page02") public String page02(){ return "success"; } /* 直接明码标价, 使用前缀来声明,通过请求转发或者重定向的方式跳转 如果使用了forward和redirect前缀来声明页面的跳转,那么springmvc不会给他们的地址加上前缀和后缀, 也就是他们不会受到前缀后缀的影响。 */ //使用请求转发跳转,必须写完整的路径 @RequestMapping("/page03") public String page03(){ return "forward:/success.jsp"; } //使用重定向跳转,必须写完整的路径 @RequestMapping("/page04") public String page04(){ return "redirect:/success.jsp"; } }
请求转发并传递数据
ModelAndView
是SpringMVC提供的组件之一,其中
Model
,模型,用于封装数据(Springmvc会把数据放到了request域中)
View
,视图,就是页面,用于展示数据如果我们设置了视图名称,并且封装了数据模型,SpringMVC会:
把Model的数据放到request域对象中,然后请求转发到指定的视图(页面)
我们可以视图页面中获取数据显示出来
使用示例
controller
//==============================下面使用ModelAndView 来返回页面和数据========================== //自己new ModelAndView对象 @RequestMapping("/page05") public ModelAndView page05(){ //构建一个视图模型对象 ModelAndView mv = new ModelAndView(); //添加数据,会存放到request域当中 mv.addObject("username","page05"); //添加页面的名字 mv.setViewName("success"); return mv; } //不自己new ModelAndView对象 @RequestMapping("/page06") public ModelAndView page06(ModelAndView mv ){ //添加数据,会存放到request域当中 mv.addObject("username","page06"); //添加页面的名字 mv.setViewName("success"); return mv; } //使用以前的方法返回页面的名字,想给页面带数据,可以写上model参数,往里面存东西即可,它会存到request域当中。 @RequestMapping("/page07") public String page07(Model model ){ //添加数据,会存放到request域当中 model.addAttribute("username","page07"); return "success"; } //使用request对象来存值 @RequestMapping("/page08") public String page08(HttpServletRequest request){ //添加数据,会存放到request域当中 request.setAttribute("username","page08"); return "success"; } //===============如果期望使用重定向跳转页面,并且也想在页面上把数据取出来显示,那么看下面的代码。! @RequestMapping("/page09") public String page09(HttpSession session){ //添加数据,会存放到session域当中 session.setAttribute("username","page09"); //要想使用重定向跳转:使用redirect: 前缀来写,要写完整的地址路径 return "redirect:/success.jsp"; }
jsp页面
<h1>success!${username}</h1> < 在视图页面中,取出数据显示出来
返回数据
直接响应字符串
两种方式
使用Servlet原生的
response
对象,返回响应数据使用
@ResponseBody
注解,把方法返回值声明成要返回的数据使用示例
//1,采用原生HttpServletResponse来写数据出去 //2. 方法没有返回值 @RequestMapping("sendData01") public void sendData01(HttpServletResponse resp) throws IOException { resp.getWriter().write("sendData01.."); } //@ResponseBody的作用:就是告诉SpringMVC,这个方法的返回值不是一个页面的名字,而是一个字符串。 @ResponseBody @RequestMapping("sendData02") public String sendData02() { return "sendData02.."; }
响应乱码处理
如果使用
@ResponseBody
响应的中文字符串,即使配置了CharacterEncodingFilter
,也会有乱码/* 1. 使用@ResponseBody表示方法的返回值是一个字符串,直接返回给页面 2. 如果方法的返回值里面有中文,那么页面收到的时候会是乱码 3. 即便我们设置了过滤器(resp.setContentType()) 也无法处理这个中文! */ @ResponseBody @RequestMapping("sendData03") public String sendData03() { return "给你发送一份数据sendData03.."; } /* 1、 当然也可以在RequestMapping里面使用属性produces来定义数据的类型 2. produces的作用就是定义了给客户端响应的数据类型和编码类型。 */ @ResponseBody @RequestMapping(value = "sendData04", produces = "text/html;charset=utf-8") public String sendData04() { return "给你发送一份数据sendData04.."; }
解决方法:在
springmvc.xml
里配置如下:
配置SpringMVC的
StringHttpMessageConverter
进行字符串处理转换,设置采用utf-8
字符集<!--开启mvc的注解驱动--> <mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="defaultCharset" value="utf-8"/> <property name="supportedMediaTypes"> <set> <value>text/plain;charset=utf-8</value> <value>text/html;charset=utf-8</value> <value>application/json;charset=utf-8</value> </set> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
返回json数据
两种方式介绍
自己把JavaBean对象转换成json格式的字符串,响应给客户端
方法返回JavaBean对象,使用
@ResponseBody
注解Springmvc帮我们转换成json格式使用示例
在pom.xml中导入依赖:
jackson-databind
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.6</version> </dependency>
springmvc.xml中开启mvc注解开关
<mvc:annotation-driven/>
controller
package com.zml.controller; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.zml.bean.User; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; //返回json数据 @Controller public class Controller03 { //返回json数据: 我们需要手动把数据(对象)转化成json字符串,然后再返回。 @ResponseBody // 让页面把方法的返回值当成字符串来对待, @RequestMapping("/sendJson01") public String sendJson01() throws JsonProcessingException { //1. 创建对象 User user = new User(1, "管理员1","123456"); //2. 把对象转化成json数据 ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(user); //3. 把数据写出去 return json; } /* 1. 如果一个方法的返回值不是String字符串,而是一个对象的类型 2. 并且这个方法上还打了注解@ResponseBody 3. 那么SpringMVC在调用执行这个方法得到返回之后,它是这样处理的: 3.1 把返回值对象,转化成json字符串,用jackson来转化 3.2 转化好了之后,把这个json字符串直接写给客户端。 */ @ResponseBody @RequestMapping("/sendJson02") public User sendJson02() throws JsonProcessingException { //1. 创建对象 User user = new User(2, "管理员2","22222"); //2. 直接返回对象 return user; } }