JavaWeb进阶修炼手册32—核心框架:SpringMVC(一)

导读:本篇文章讲解 JavaWeb进阶修炼手册32—核心框架:SpringMVC(一),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

1. 今日内容

2. SpringMVC概述

2.1 SpringMVC

1. SpringMVC是应用于表现层的框架。

2. MVC 全名是 Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写, 是一种用于设计创建 Web 应用程序表现层的模式。MVC 中每个部分各司其职: 
	1. Model(模型): 
		* 通常指的就是我们的数据模型。作用一般情况下用于封装数据。 
	2. View(视图): 
		* 通常指的就是我们的 jsp 或者 html。作用一般就是展示数据的。 
	3. Controller(控制器): 
		* 是应用程序中处理用户交互的部分。作用一般就是处理程序逻辑的,比如验证信息、跳转到哪个页面等等。

3. 优点:
	清晰的角色划分: 
		前端控制器(DispatcherServlet)  
		请求到处理器映射(HandlerMapping)  
		处理器适配器(HandlerAdapter)  
		视图解析器(ViewResolver)  
		处理器或页面控制器(Controller)  
		验证器( Validator)  
		命令对象(Command  请求参数绑定到的对象就叫命令对象)  
		表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。

SpringMVC 在三层架构的位置 :
在这里插入图片描述

2.1 SpringMVC和Struts2 的优略分析

在这里插入图片描述

3. SpringMVC入门案例

3.1 建立项目,并将项目结构补充完整

点击新建项目。出现如下图:
在这里插入图片描述
接着选择项目的生成的坐标:
在这里插入图片描述
在这里插入图片描述
上面的键值对如下:

archetypeCatalog internal

生成的项目结构如下:
在这里插入图片描述
接着,将项目的结构补充完整:
在这里插入图片描述
在这里插入图片描述

最终完整的项目结构如下:
在这里插入图片描述

3.2 配置项目

3.2.1 在pom.xml中导入SpringMVC依赖jar包

在这里插入图片描述
再在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>

再在build标签内粘贴以下代码:

		<!--配置插件-->
        <plugins>
            <!-- java编译插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <!-- Tomcat插件 -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <!-- 项目访问路径 -->
                    <path>/springmvc</path>
                    <!-- 访问项目的端口号 -->
                    <port>80</port>
                </configuration>
            </plugin>

        </plugins>

3.2.2 创建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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    

</beans>

再点击一下右上角的config提示。

3.2.3 在web.xml中配置核心控制器DispatcherServlet

<!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>

    <!--解决中文乱码的问题-->
    <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>
        <!-- 启动过滤器 -->
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- SpringMVC的核心控制器 -->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 配置Servlet的初始化参数,读取springmvc的配置文件,创建spring容器 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>  <!-- 这个名字必须是contextConfigLocation -->
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <!-- 配置servlet启动时加载对象 -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>   <!-- / 表示拦截所有请求交给dispatcherServlet处理 -->
    </servlet-mapping>

</web-app>

3.2.4 配置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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 配置spring创建容器时要扫描的包 -->
    <context:component-scan base-package="cn.wanghao.springmvc"></context:component-scan>

    <!-- 注解如何找到。  配置spring开启注解mvc的支持。注解驱动,以使得访问路径与方法的匹配可以通过注解配置 -->
    <mvc:annotation-driven></mvc:annotation-driven>

    <!-- 注解的方法返回的字符串如何找到对应的页面。  配置视图解析器 -->
    <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>

</beans>

3.2.5 编写控制器类

package cn.wanghao.springmvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/hello")
public class helloController {

    @RequestMapping("/sayHello")
    public String sayHello(){
        System.out.println("hello springMVC!!!");
        return "success";
    }

}

3.2.6 编写index.jsp

先将项目自动生成的index.jsp删除,再从新键一个,然后编写:

<%--
  Created by IntelliJ IDEA.
  User: WangHao
  Date: 2020/3/21
  Time: 13:47
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

    <a href="hello/sayHello">springMVC入门案例</a>
</body>
</html>

3.3 案例效果

在这里插入图片描述

3.4 入门案例的执行流程

1. 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象, 就会加载springmvc.xml配置文件 

2. 开启了注解扫描,那么HelloController对象就会被创建 

3. 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解 找到执行的具体方法 

4. 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件 

5. Tomcat服务器渲染页面,做出响应 

4. SpringMVC执行过程

在这里插入图片描述

1. DispatcherServlet:前端控制器 
	* 用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由 它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。 

2.  HandlerMapping:处理器映射器 
	* HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的 映射方式,例如:配置文件方式,实现接口方式,注解方式等。 

3. HandlAdapter:处理器适配器 
	* 通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理 器进行执行。 

4. Handler:处理器 
	* 它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由 Handler 对具体的用户请求进行处理。即用来执行我们编写的代码。

5. View Resolver:视图解析器 
	* 根据处理器返回的字符串(逻辑视图),找到该页面(物理视图)。

6. View:视图 
	* SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView 等。我们最常用的视图就是 jsp。 

除了dispatcaherServlet是在web.xml配置外。其余的什么器都是其类或者自定义其继承类,在springmvc.xml中用bean标签实例化就构成了什么什么器,

5. SpringMVC细节

5.1 mvc:annotation-driven说明

在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。

使用mvc:annotation-driven 自动加载 RequestMappingHandlerMapping (处理映射器)和 RequestMappingHandlerAdapter ( 处 理 适 配 器 ), 所以视图解析器需要我们自己建立。

一般开发中,我们都需要写上此标签(虽然从入门案例中看,我们不写也行,随着课程的深入,该标签还 有具体的使用场景)。

5.2 RequestMapping注解

1. 作用:用于建立url和处理请求方法之间的对应关系
2. 出现位置:
	1. 类上
		* 请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。 
	2. 类的方法上
		* 请求 URL 的第二级访问目录。 写的话需要以/开头。 

		* 举例:
				@Controller
				@RequestMapping("/hello")
				public class helloController {
				
				    @RequestMapping("/sayHello")
				    public String sayHello(){
				        System.out.println("hello springMVC!!!");
				        return "success";
				    }
				
				}

			访问路径: 项目路径/hello/sqyHello

	3. 属性: 可以点进RequestMapping类中去看
		1. path:配置访问目录。
		2. value:用于指定请求的 URL。它和 path 属性的作用是一样的。 
		3. method:用于指定请求的方式。 
			eg:method = {RequestMethod.POST}  post请求才接受
		4. params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和 配置的一模一样。也可以只设置key。但是我们一般不用他做参数检验,因为不一样页面会出错。
			eg :
				1. params = {"accountName"},表示请求参数必须有 accountName 
				2. params = {"moeny!100"},表示请求参数中 money 不能是 100。
				3. params = {"moeny=100"},表示请求参数中 money 必须是 100。  
		5. headers:用于指定限制请求消息头的条件。 没有就会报错。
			eg:headers = {“accept”}

浏览器访问会在项目路径后面带上/, 项目里面不带。

5.3 请求参数的绑定

如果在被注解的控制器类的方法中定义参数,则springMVC会自动的将前端参数映射到类的形参中。

1. 绑定的机制 
	* 我们都知道,表单中请求参数都是基于 key=value 的。 SpringMVC 绑定请求参数的过程是通过把表单提交请求参数,自动的转换为控制器中方法的形参的值。 
	* 例如:
		<a href="account/findAccount?accountId=10">查询账户</a> 中参数是:accountId=10

		@RequestMapping("/findAccount") 
		public String findAccount(Integer accountId) { 
			System.out.println("查询了账户。。。。"+accountId); 
			return "success"; 
		}

		结果: 查询了账户。。。。10

2. 支持的数据类型
	1. 基本类型和 String 类型 
	2. 实体类(包括实体类中属性为其他的实体类)
	3. 包括 List 结构和 Map 结构的集合(包括数组)
		* 注意:SpringMVC 绑定请求参数是自动实现的,但是要想使用,必须遵循使用要求。 

3. 使用要求
	1. 如果是基本类型或者 String类型:
		* 要求我们的参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写) 

	2.  如果是实体类类型:
		* 要求表单中参数名称和实体类的属性名称保持一致。并且控制器方法的参数类型是实体类 类型
		* 比如:
				方法的形参是:User user         且User类中有属性username、password和一个Account类型的属性acccount。Account类中有属性meney。
				前端标签是:
					<input type="text" name="username">
					<input type="text" name="password">
					<input type="text" name="acccount.meney">

	3.  List 结构和 Map 结构的集合:
		1. 第一种: 
			要求集合类型的请求参数必须在 实体类 中。在表单中请求参数名称要和 实体类 中集合属性名称相同。
			给 List 集合中的元素赋值,使用下标。 
			给 Map 集合中的元素赋值,使用键值对。 

			eg :
				方法的形参是:User user    且User类中有属性list<Account> accounts和Map<String, Account> accountsMap。Account类中有属性meney
				前端标签是:
					<input type="text" name="accounts[0].meney">
					<input type="text" name="accountsMap["one"].meney">

注意:请求参数的绑定对于post和get请求都可以。

5.4 自定义类型转换器

首先,需要知道springMVC会自动将前端的字符串参数转换为被注解的方法的形参类型。其实内部是使用转换器实现的。但是,在开发的过程中,我们可能遇到类型无法转换的问题,这个时候就需要我们自己来定义类型转换器,使用自己的类型转换器来转换。
比如,如果前端输入的参数是:2020-3-21,这个就无法转换,2020/3/21可以。报的错误如下:
在这里插入图片描述
接下来介绍如何自定义类型转换器 :

  1. 第一步:定义一个类,实现 Converter 接口,该接口有两个泛型。 该接口定义如下:
    在这里插入图片描述
package cn.wanghao.springmvc.utils;

import org.springframework.core.convert.converter.Converter;
import org.springframework.util.StringUtils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class StringToDateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String source) {
        if (StringUtils.isEmpty(source)) {
            throw new NullPointerException("请输入要转换的日期");
        }
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        try {
            Date date = df.parse(source);
            return date;
        } catch (ParseException e) {
            throw new RuntimeException("输入日期有误");
        }
    }
}

  1. 第二步:在 spring配置文件中配置类型转换器。
    spring 配置类型转换器的机制是,将自定义的转换器注册到类型转换服务中去。
<!--配置自定义类型转换器-->
    <bean id="converterService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <array>
                <bean class="cn.wanghao.springmvc.utils.StringToDateConverter"></bean>
            </array>
        </property>
    </bean>
  1. 第三步:在 annotation-driven标签中引用配置conversion-service属性
<mvc:annotation-driven conversion-service="converterService"></mvc:annotation-driven>

这样,用户输入2020-3-21,就能够转换了,但是如果输入2020/3/21不能转换了。

这是因为从StringDate类型的转换器被我们自己写的从StringDate类型的转换器覆盖了。

5.5 使用 ServletAPI 对象作为方法参数

SpringMVC 还支持使用原始 ServletAPI 对象作为控制器方法的参数。支持原始 ServletAPI 对象有: 
	HttpServletRequest 
	HttpServletResponse 
	HttpSession 
	java.security.Principal 
	Locale 
	InputStream
	OutputStream
	Reader 
	Writer 

我们可以把上述对象,直接写在控制的方法参数中使用。 

例如:
	@RequestMapping("/testServletAPI") 
	public String testServletAPI(HttpServletRequest request, 			HttpServletResponse response, HttpSession session) { 
		System.out.println(request); 
		System.out.println(response);  
		System.out.println(session); 
		return "success"; 
	}

6. 常用注解

6.1 @RequestParam()

1. 作用:
	1. 为前端传来的参数取别名
	2. 之前如果前端传的参数个数不等于关于前端参数的形参个数,不会报错。所以required属性没多大用。
		现在可以通过required属性设置,不是必须的,那么缺少就不会报错。
2. 属性:
	1. value:请求参数中的名称。 
	2. required:请求参数中是否必须提供此参数。默认值:true可以不写。表示必须提供,如果不提供将报错。 

注意:@RequestParam Map<String, Object> map 可以获取所有的参数,以键值对的形式存放在map中。

例子:
在这里插入图片描述

6.2 @ RequestBody

1. 作用:
	用于获取请求体内容。直接使用得到是 key=value&key=value...字符串结构的数据。 
	get 请求方式不适用。 
2. 属性:
	* required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值 为 false,get 请求得到是 null。

注意:@RequestBody Map<String, Object> map 可以获取所有的请求体中的参数,以键值对的形式存放在map中。

案例:
在这里插入图片描述
如果要将请求体中的参数封装成Map结构,可以这样写:
public String useRequestBody(@RequestBody(required = false) Map<String, Object> param){ }

6.3 @PathVaribale

1. 作用:用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符。  url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。 
2. 属性:
	1. value:用于指定 url 中占位符名称。  
	2. required:是否必须提供占位符。

在这里插入图片描述

6.4 @RequestHeader()

1. 作用:
	* 用于获取消息头。
2. 属性:
	1. value:提供消息头名称 
	2. required:是否必须有此消息头 

	注意:在实际开发中一般不怎么用。 

注意:@RequestHeader Map<String, Object> map 可以获取所有的请求头中的参数,以键值对的形式存放在map中。

例子:
在这里插入图片描述

6.5 @CookieValue()

1. 作用:
	* 指定要获取的cookie的名称,从而获取该cookie的值
2. 属性:
	1. value:指定 cookie 的名称
	2. required:是否必须有此 cookie。 

注意:要获取所有的cookie目前不能通过注释,要先获取原生servlet的reques,再用request.getCookies();

例子:
在这里插入图片描述

6.6 @ ModelAttribute

1. 作用:
	1. 出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。如果该方法有返回值,则
	2. 出现在参数上,获取指定的数据给参数赋值。 
	
	* 注意:@ModelAttribute最主要的作用是将数据添加到模型对象中,用于视图页面展示时使用。

2. 属性:
	value:用于获取数据的 key。
		@ ModelAttribute(value = "one") 修饰在方法上,是设置值
		@ ModelAttribute(value = "one") 修饰在参数上,是取值

3. 应用场景: 
	* 当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。 
	* 例如: 
			我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数 据是肯定没有此字段的内容,
			一旦更新会把该字段内容置为 null,此时就可以使用此注解解决问题。

@ModelAttribute最主要的作用是将数据添加到模型对象中,用于视图页面展示时使用。

@ModelAttribute等价于 model.addAttribute(“attributeName”, abc); 但是根据@ModelAttribute注释的位置不同,和其他注解组合使用,致使含义有所不同。具体区别如下:

6.6.1 @ModelAttribute注释方法

例子(1),(2),(3)类似,但是(3)这种形式用的最多。被@ModelAttribute注释的方法会在此controller每个方法执行前被执行,因此对于一个controller映射多个URL的用法来说,要谨慎使用。

Mode可以理解为jsp这种展示页面。

(1)@ModelAttribute注释void返回值的方法

@Controller 
public class HelloWorldController { 
    @ModelAttribute 
    public void populateModel(@RequestParam String abc, Model model) { 
         model.addAttribute("attributeName", abc); 
      } 

    @RequestMapping(value = "/helloWorld") 
    public String helloWorld(@ModelAttribute("attributeName") String str) { 
    	System.out.println(str);
        return "helloWorld"; 
    } 
 }

这个例子,在获得请求/helloWorld 后,populateModel方法在helloWorld方法之前先被调用,它把abc加入到一个名为attributeName的model属性中,在它执行后 helloWorld被调用,可以使用@ModelAttribute(value = “attributeName”)将数据拿出来。helloWorld被调用后返回视图名helloWorld和model已由@ModelAttribute方法生产好了。

这个例子中model属性名称和model属性对象有model.addAttribute()实现,不过前提是要在方法中加入一个Model类型的参数。
当URL或者post中不包含次参数时,会报错,其实不需要这个方法,完全可以把请求的方法写成,这样缺少此参数也不会出错

@RequestMapping(value = "/helloWorld") 
public String helloWorld(String abc) { 
    return "helloWorld"; 
}

(2)@ModelAttribute注释返回具体类的方法

@ModelAttribute 
public Account addAccount(@RequestParam String number) { 
    return accountManager.findAccount(number); 
}

这种情况,model属性的名称没有指定,它由返回类型隐含表示,如这个方法返回Account类型,那么这个model属性的名称是account。

(3)@ModelAttribute(value=””)注释返回具体类的方法

@Controller 
public class HelloWorldController { 
    @ModelAttribute("attributeName") 
    public String addAccount(@RequestParam String abc) { 
        return abc; 
      } 

    @RequestMapping(value = "/helloWorld") 
    public String helloWorld() { 
        return "helloWorld"; 
    } 
}

这个例子中使用@ModelAttribute注释的value属性,来指定model属性的名称。model的attributeName属性的值就是方法的返回值。它无须要特定的参数。

(4)@ModelAttribute和@RequestMapping同时注释一个方法

@Controller 
public class HelloWorldController { 
    @RequestMapping(value = "/helloWorld.do") 
    @ModelAttribute("attributeName") 
    public String helloWorld() { 
         return "hi"; 
      } 
  }

这时这个方法的返回值并不是表示一个视图名称,而是model属性的值,视图名称由RequestToViewNameTranslator根据请求”/helloWorld.do”转换为逻辑视图helloWorld。
Model属性名称有@ModelAttribute(value=””)指定,相当于在request中封装了key=attributeName,value=hi。

6.6.2 @ModelAttribute注释一个方法的参数

@Controller 
public class HelloWorldController { 
    @ModelAttribute("user") 
    public User addAccount() { 
        return new User("jz","123"); 
     } 

    @RequestMapping(value = "/helloWorld") 
    public String helloWorld(@ModelAttribute("user") User user) { 
           user.setUserName("jizhou"); 
           return "helloWorld"; 
        } 
  }

在这个例子里,@ModelAttribute(“user”) User user注释方法参数,参数user的值来源于addAccount()方法中的model属性。
此时如果方法体没有标注@SessionAttributes(“user”),那么scope为request,如果标注了,那么scope为session

6.6.3 @ModelAttribute应用的例子

背景需求如下,当更新一个对象时,某个字段比如密码不能被修改。
常见解决思路有二:
① new 一个对象,form表单中密码域为隐藏域,该种方法有风险。

② new 一个对象,在更新的时候再次从数据库查询密码从而进行更新,该方法比较麻烦。

SpringMVC的解决思路:使用@ModelAttribute !

/该方法模拟根据id从数据库获取对象。
@ModelAttribute
public void getUser(@RequestParam(value="id",required=false) Integer id, Map<String, Object> map){
	if(id != null){
		//模拟从数据库中获取对象
		User user = new User(1, "Tom", "123456", "tom@baidu.com", 12);
		System.out.println("从数据库中获取一个对象: " + user);
		
		map.put("user", user);
	}
}
//根据表单name属性值对model中的user对象进行更新。因为表单域没有密码,故密码使用数据库查询得到的。
@RequestMapping("/testModelAttribute")
public String testModelAttribute(@ModelAttribute("user") User user){
	System.out.println("修改: " + user);
	return "SUCCESS";
}

结果:
从数据库中获取一个对象: User [username=Tom, password=123456, email=tom@baidu.com, age=12, address=null]

修改: User [username=Tom, password=123456, email=tom@baidu.com, age=18, address=null]

6.7 补充说明Model

对于@RequestMapping@ModelAttribute注解的方法,方法里面可以写形参Model model,这个model代表是是request域对象, 可以通过model.addAttribute()来添加属性以及属性值。

@ModelAttribute注解的方法返回值最终也是存放在Model中。

Model 是 spring 提供的一个接口,该接口有一个实现类 ExtendedModelMap,该类继承了 ModelMap,而 ModelMap 就是 LinkedHashMap 子类。

因此,对于@RequestMapping@ModelAttribute注解的方法,方法里面可以写形参Model model或者ModelMap modelMap或者Map<String, Object> map
比如:

@Controller 
public class HelloWorldController { 
    @ModelAttribute 
    public void populateModel(@RequestParam String abc, Model model) { 
         model.addAttribute("attributeName", abc); 
      } 

    @RequestMapping(value = "/helloWorld") 
    public String helloWorld(@ModelAttribute("attributeName") String str) { 
    	System.out.println(str);
        return "helloWorld"; 
    } 
 }

等价于:

@Controller 
public class HelloWorldController { 
    @ModelAttribute 
    public void populateModel(@RequestParam String abc, ModelMap modelMap) { 
         modelMap.addAttribute("attributeName", abc); 
      } 

    @RequestMapping(value = "/helloWorld") 
    public String helloWorld(@ModelAttribute("attributeName") String str) { 
    	System.out.println(str);
        return "helloWorld"; 
    } 
 }

等价于

@Controller 
public class HelloWorldController { 
    @ModelAttribute 
    public void populateModel(@RequestParam String abc, Map<String, Object> map) { 
         map.put("attributeName", abc); 
      } 

    @RequestMapping(value = "/helloWorld") 
    public String helloWorld(@ModelAttribute("attributeName") String str) { 
    	System.out.println(str);
        return "helloWorld"; 
    } 
 }

另外,Model类无法进行取值,如果在控制器中取出Model的属性值,可以用其子类,ModelMap, 用modelMap.get()获取。

建议:

  1. 使用ModelMap,少使用Model 和 Map
  2. 取值的时候用@ModelAttribute或者ModelMap

6.8 @SessionAttribute

1. 作用:
	* 用于多次执行控制器方法间的参数共享。 即多次请求间共享参数。

2. 位置:
	* 只能注解于类上

3. 属性:
	1. value:用于指定存入的属性名称 
	2. type:用于指定存入的数据类型。 

* 说明:value一般为model(request)中的key,他会将model中的这个键值对复制到session域对象中,在jsp页面中使用。

* 清空session域的键值对:
	方法参数用SessionStatus, 用 sessionStatus.setComplete(); 清空

案例:
在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/84652.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!