前面我们学习了关于sprimgmvc的组件和请求方式,今天来学习获取请求参数和向域对象共享数据。
目录
3.1 使用ServletAPI向request域对象共享数据
3.2 使用ModelAndView向request域对象共享数据
1.入门案例
先写一个案例熟悉一下springmvc的流程。
- 浏览器发送请求,若请求地址符合前端控制器的url-pattern,该请求就会被前端控制器DispatcherServlet处理。
- 前端控制器会读取SpringMVC的核心配置文件,通过扫描组件找到控制器,将请求地址和控制器中@RequestMapping注解的value属性值进行匹配,
- 若匹配成功,该注解所标识的控制器方法就是处理请求的方法。
- 处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析,加上前缀和后缀组成视图的路径,
- 通过Thymeleaf对视图进行渲染,最终转发到视图所对应页面
1.1 创建Maven工程
1.2 添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>mybatis</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring_mvc_hello</artifactId>
<packaging>war</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies> <!-- SpringMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.1</version>
</dependency> <!-- 日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency> <!-- ServletAPI -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency> <!-- Spring5和Thymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
</dependencies>
</project>
注:由于 Maven 的传递性,我们不必将所有需要的包全部配置依赖,而是配置最顶端的依赖,其他靠传递性导入。
1.3配置web.xml
注册SpringMVC的前端控制器DispatcherServlet
1.默认配置
此配置作用下,SpringMVC的配置文件默认位于WEB-INF下,默认名称为<servlet-name>-
servlet.xml,例如,以下配置所对应SpringMVC的配置文件位于WEB-INF下,文件名为springMVC-servlet.xml
<!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 -->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet- class>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<!--设置springMVC的核心控制器所能处理的请求的请求路径 /所匹配的请求可以是/login或.html或.js或.css方式的请求路径 但是/不能匹配.jsp请求路径的请求 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
2.拓展方式
可通过init-param标签设置SpringMVC配置文件的位置和名称,通过load-on-startup标签设置
SpringMVC前端控制器DispatcherServlet的初始化时间
<init-param>
<!-- contextConfigLocation为固定值 -->
<param-name>contextConfigLocation</param-name>
<!-- 使用classpath:表示从类路径查找配置文件,例如maven工程中的 src/main/resources -->
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--作为框架的核心组件,在启动过程中有大量的初始化操作要做 而这些操作放在第一次请求时才执行会严重影响访问速度 因此需要通过此标签将启动控制DispatcherServlet的初始化时间提前到服务器启动时 -->
<load-on-startup>1</load-on-startup>
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置springmvc配置文件的名称和位置-->
<init-param>
<!-- contextConfigLocation为固定值 -->
<param-name>contextConfigLocation</param-name>
<!-- 使用classpath:表示从类路径查找配置文件,例如maven工程中的 src/main/resources -->
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--作为框架的核心组件,在启动过程中有大量的初始化操作要做 而这些操作放在第一次请求时才执行会严重影响访问速度 因此需要通过此标签将启动控制DispatcherServlet的初始化时间提前到服务器启动时 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<!--
url-pattern中/和/*的区别
/ 匹配浏览器向服务器发送的所有请求(不包括jsp)
/* 匹配浏览器向服务器发送的所有请求(包括jsp)
-->
<!--设置springMVC的核心控制器所能处理的请求的请求路径 /所匹配的请求可以是/login或.html或.js或.css方式的请求路径 但是/不能匹配.jsp请求路径的请求 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--
url-pattern中/和/*的区别
/ 匹配浏览器向服务器发送的所有请求(不包括jsp)
/* 匹配浏览器向服务器发送的所有请求(包括jsp)
-->
<!--设置springMVC的核心控制器所能处理的请求的请求路径 /所匹配的请求可以是/login或.html或.js或.css方式的请求路径 但是/不能匹配.jsp请求路径的请求 -->
1.4 创建请求控制器
由于前端控制器对浏览器发送的请求进行了统一的处理,但是具体的请求有不同的处理过程,因此需要创建处理具体请求的类,即请求控制器请求控制器中每一个处理请求的方法成为控制器方法因为SpringMVC的控制器由一个POJO(普通的Java类)担任,因此需要通过@Controller注解将其标识为一个控制层组件,交给Spring的IoC容器管理,此时SpringMVC才能够识别控制器的存在
@Controller
public class HelloController {
}
1.5 创建SpringMVC的配置文件
配置视图解析器
<!--扫描控制层组件-->
<context:component-scan base-package="com.xiaoye"></context:component-scan>
<!-- 配置Thymeleaf视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/templates/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
</property>
</bean>
</property>
</bean>
配置默认的servlet处理静态资源 当前工程web.xml配置的前端控制器的url-pattern是/ tomcat的默认的DefaultServlet的url-pattern也是/ 此时浏览器发送的请求会优先被前端控制器处理,但是他不能处理静态资源 所以可以使用<mvc:default-servlet-handler/>使用默认浏览器,需要 再加上 <mvc:annotation-driven />,不然所有请求都会被DefaultServlet处理 加了后,浏览器的请求会先被前端控制器处理,后被默认的处理
<!--配置默认的servlet处理静态资源
当前工程web.xml配置的前端控制器的url-pattern是/
tomcat的默认的DefaultServlet的url-pattern也是/
此时浏览器发送的请求会优先被前端控制器处理,但是他不能处理静态资源
所以可以使用<mvc:default-servlet-handler/>使用默认浏览器,需要
再加上 <mvc:annotation-driven />,不然所有请求都会被DefaultServlet处理
加了后,浏览器的请求会先被前端控制器处理,后被默认的处理
-->
<mvc:default-servlet-handler/>
-视图控制器:为当前请求直接设置视图名称实现页面跳转 设置后,则只有视图控制器设置的请求会被处理,其他会404, 可通过设置一个标签 <mvc:annotation-driven />解决
<!--开启mvc注解驱动-->
<mvc:annotation-driven />
<!--视图控制器:为当前请求直接设置视图名称实现页面跳转
设置后,则只有视图控制器设置的请求会被处理,其他会404,
可通过设置一个标签 <mvc:annotation-driven />解决
-->
<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
<mvc:view-controller path="/to/add" view-name="employee_add"></mvc:view-controller>
1.6 测试
1.实现对首页的访问
在请求控制器中创建处理请求的方法,使用return跳到登录页面
此时renturn里受Thymeleaf视图解析器解析,会自动加上我们在配置文件设置的视图前缀和后缀
// @RequestMapping注解:处理请求和控制器方法之间的映射关系
// @RequestMapping注解的value属性可以通过请求地址匹配请求,/表示的当前工程的上下文路径
// localhost:8080/springMVC/
@RequestMapping("/")
public String index() {
//设置视图名称
return "index";
}
2.通过超链接跳转到指定页面
在主页index.html中设置超链接
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>index.html</h1>
<a th:href="@{/hello}">测试SpringMVC</a>
</body>
</html>
在请求控制器中创建处理请求的方法
@RequestMapping("/hello")
public String hello(){
return "successs";
}
}
2.获取请求参数
2.1 通过ServletAPI获取
将HttpServletRequest作为控制器方法的形参,此时HttpServletRequest类型的参数表示封装了当前请求的请求报文的对象
<form th:action="@{/param/servletAPI}" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录"><br>
@RequestMapping("/param/servletAPI")
public String getParamServletAPI(HttpServletRequest request) {
HttpSession session = request.getSession();
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("username:" + username + ",password:" + password);
return "success";
}
2.2 通过控制器方法的形参获取请求参数
在控制器方法的形参位置,设置和请求参数同名的形参,当浏览器发送请求,匹配到请求映射时,在DispatcherServlet中就会将请求参数赋值给相应的形参
<a th:href="@{/testParam(username='admin',password=123456)}">/testParam</a><br>
@RequestMapping("/testParam")
public String testParam(String username, String password) {
System.out.println("username:" + username + ",password:" + password);
return "success";
}
注:
若请求所传输的请求参数中有多个同名的请求参数,此时可以在控制器方法的形参中设置字符串
数组或者字符串类型的形参接收此请求参数
若使用字符串数组类型的形参,此参数的数组中包含了每一个数据
若使用字符串类型的形参,此参数的值为每个数据中间使用逗号拼接的结果
2.3 通过实体类获取参数
可以在控制器方法的形参位置设置一个实体类类型的形参,此时若浏览器传输的请求参数的参数名和实体类中的属性名一致,那么请求参数就会为此属性赋值
</form><form th:action="@{/param/pojo}" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录"><br>
</form>
@RequestMapping("/param/pojo")
public String getParamByPojo(User user) {
System.out.println(user);
return "success";
}
3.域对象共享数据
3.1 使用ServletAPI向request域对象共享数据
request.setAttribute
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request) {
request.setAttribute("testScope", "hello,servletAPI");
return "success";
}
3.2 使用ModelAndView向request域对象共享数据
@RequestMapping("/test/mav")
public ModelAndView testMAV() {
/**
* 向域对象共享数据:
* 1,ModelAndView:具有Model和View功能
* model:向请求域共享数据
* view:设置逻辑视图实现页面跳转
* 2.使用Model向请求域共享数据
* 3.使用ModelMap向请求域共享数据
* 4.使用map向请求域共享数据
* 5.model和modelMap的关系
* 在底层中,这类型的形参最终都是通过BindingAwareModelMap创建
*/
ModelAndView mav = new ModelAndView();
mav.addObject("testRequestScope", "hello,ModelAndView");
mav.setViewName("success");
return mav;
}
3.3 使用Model向request域对象共享数据
model.addAttribute
@RequestMapping("/test/model")
public String testModel(Model model) {
model.addAttribute("testRequestScope", "hello,Model");
return "success";
}
3.4 使用map向request域对象共享数据
map.put
@RequestMapping("/test/map")
public String testmap(Map<String, Object> map) {
map.put("testRequestScope", "hello,map");
return "success";
}
3.5 使用ModelMap向request域对象共享数据
@RequestMapping("/test/modelmap")
public String testModelmap(ModelMap modelmap) {
modelmap.addAttribute("testRequestScope", "hello,Modelmap");
return "success";
}
3.6 Model,ModelMap,Map,之间的关系
Model、ModelMap、Map类型的参数其实本质上都是 BindingAwareModelMap 类型的
public interface Model{}
public class ModelMap extends LinkedHashMap<String, Object> {}
public class ExtendedModelMap extends ModelMap implements Model {}
public class BindingAwareModelMap extends ExtendedModelMap {}
3.7 向Session域共享数据
@RequestMapping("/test/session")
public String testsession(HttpSession session){
session.setAttribute("testSession","hello,session");
return "success";
3.8 向application域共享数据
@RequestMapping("/testApplication")
public String testApplication(HttpSession session) {
ServletContext application = session.getServletContext();
application.setAttribute("testApplicationScope", "hello,application");
return "success";
}