SpringMVC之一_请求相关

笔记基于以下教程,包括:SpringMVC之一_请求相关、SpringMVC之二_响应相关
SpringMVC视频教程:https://www.bilibili.com/video/BV1Sb411s7qa

更新:
1.该教程是基于注解+XML的方式,讲得不够透彻和全面:mvc:annotation-driven含糊带过,数据验证、文件下载、HttpMessageConverter没讲。
2.个人觉得,学的时候还是应该学基于XML的,用的时候用基于注解的。直接学基于注解开发就像浮在面上,框架自动干了太多事了。
3.根据以下SpringMVC教程查漏补缺:

https://www.bilibili.com/video/BV1tW411q7dx
https://www.bilibili.com/video/BV1mW411M7YA

一 背景知识

服务器端三层架构:
表现层、业务层、持久层
在这里插入图片描述

表现层的MVC设计模型:
M:model模型,JavaBean
V:view视图,JSP
C:controller控制器,Servlet
控制器接收请求,用JavaBean封装请求中的数据,再传递给业务层处理;
业务层处理后返回的结果,用JavaBean封装,再传给控制器;
控制器再将JavaBean转发给JSP,JSP生成页面,响应给浏览器;
【注意:JSP页面是放在服务器上的,且通过页面解析器连接到了请求响应的整个流程中,所以JSP页面中是可以使用请求响应中的变量的;具体来说就是四大作用域中的变量:page、request、session、application】

SpringMVC框架:
基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,是目前最主流的MVC框架之一,支持RESTful编程风格。

在这里插入图片描述

SpringMVC的优势:
模块化,角色划分清晰:
前端控制器:DispacherServlet,SpringMVC的入口是Servlet
处理器映射器:HandlerMapping
处理器适配器:HandlerAdapter
视图解析器:ViewResovler
处理器或页面控制器:Controller
验证器:Validator
命令对象:Command,请求参数绑定到的对象就叫命令对象
表单对象:Form Object,提供给表单展示和提交到的对象就叫表单对象

二 SpringMVC入门程序

在这里插入图片描述
本项目混合使用Spring XML配置文件和Spring 注解来进行开发

2.1 搭建开发环境:

1.创建maven工程
选择骨架构建、webapp:创建后有web.xml、index.jsp、pom.xml
注意:这个选项是apach…webapp,不要选错了
在这里插入图片描述
项目创建后需要手动创建java、resource目录,并且在项目结构中分别指定为source目录、resource目录
在这里插入图片描述
resource目录中创建spring框架的配置文件:
右键——new—— XML Configuration File —— spring config
创建的xml配置文件自动带约束
注意:如果没有spring config这个选项,解决如下:

https://www.cnblogs.com/chenmingjun/p/10920813.html

在这里插入图片描述

导入依赖:pom.xml

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <spring.version>5.0.2.RELEASE</spring.version>
  </properties>
  
  <dependencies>
    <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>

配置前端控制器:SpringMVC的入口,web.xml

<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>
  </servlet>

  <!-- Servlet负责处理的请求路径-->
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

项目部署到tomcat:
Edit Configuration—— Add NewConfiguration —— Tomcat Server —— Server/Deployment
在这里插入图片描述
在这里插入图片描述
运行项目,可通过localhost:8080访问index.jsp

2.2 入门代码

这里才是开始写Controller、Service、DAO;创建SpringBoot项目时,上面的过程都由框架自动完成了

1.springConfig.xml 【让IOC容器认识SpringMVC注解,扫描到注解】
加入spring核心容器、spring注解相关的约束;
启动对springMVC注解的支持;
设置包扫描;

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       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.test"></context:component-scan>

    <!-- 开启对SpringMVC框架注解的支持-->
    <mvc:annotation-driven/>
</beans>

2.加载springConfig.xml配置文件:web.xml
在之前spring_ioc教程中,是通过在main程序中手动利用ApplicationContext接口的实现类来加载配置文件的。
现在创建的SpringMVC项目,就和之前初学JavaWeb项目一样,整个项目压根没有显式的main程序入口,项目是由tomcat服务器来启动和调用的。
前面有提到,DispatcherServlet是SpringMVC项目的入口,所以要想在项目最开始加载spring配置文件,应该由DispatcherServlet来加载spring配置文件。

  <!-- 前端控制器-->
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 配置初始化参数,为DispatcherServlet对象创建contextConfigLocation属性,值为classpath:springConfig.xml-->
    <!-- 这样,DispatcherServlet初始化时就会加载spring配置文件-->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springConfig.xml</param-value>
    </init-param>
    <!-- servlet正常情况下是第一次接收请求时创建,load-on-startup配置后,可以在项目启动时立刻创建-->
    <load-on-startup>1</load-on-startup>
  </servlet>

3.创建处理器Handler(controller)
@Controller:spring框架中的注解
@RequestMapping:springMVC框架中的注解

@RequestMapping修饰的方法返回值为String类型"XXX"时,SpringMVC框架自动视为"XXX.jsp",并找到该页面然后返回,实现了页面跳转。

但是,SpringMVC框架去哪找这个XXX.jsp页面?
通过视图解析器配置查找的方法。

4.配置视图解析器:springMVC.config

视图解析器:将逻辑视图映射为JSP文件,说人话就是,自动根据字符串"mypage"找"…/mypage.jsp"。
注意:视图解析器听起来很牛逼,乍一听以为是解析jsp文件本身的,其实只是解析字符串的。

一般将JSP页面放在/WEB-INF/pages目录下
在这里插入图片描述

    <!-- 视图解析器-->
    <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>

2.3 入门程序流程

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

DispatcherServlet:前端控制器
用户请求到达前端控制器,相当于MVC模式中的C,dispatcherServlet是整个流程控制的中心,由它调用其他组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合;

HandlerMapping:处理器映射器
HandlerMapping负责根据用户请求找到Handler即处理器,SpringMVC提供了不同的映射器实现不同的映射方式,例如:配置文件方式、实现接口方式、注解方式;
【根据请求路径,判断由哪个Controller中的哪个RequestMapping方法来处理请求】

Handler:处理器(@Controller)
它就是我们开发中要编写的具体业务控制器,即@Controller修饰的方法,由DispatcherServlet把用户请求转发到Handler,由Handler对具体的用户请求进行处理;

HandlerAdapter:处理器适配器
将Controller转为适配器,通过HandlerAdapter对处理器进行执行,是适配器设计模式的应用,扩展适配器可以对更多类型的处理器进行执行;

ViewResolver:视图解析器
负责将处理结果生成View视图,首先根据逻辑视图名称解析成物理视图名,即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户;
【也就是说,不仅干了由Controller返回值找对应JSP的工作,JSP渲染成HTML也是视图解析器干的】

View:视图
springMVC框架提供了很多的View视图类型的支持,包括:jstView、freemarkerView、pdfView,jsp;
一般情况下,需要通过页面标签或页面模板技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体页面;

<mvc:annotation-driven/> 说明:
SpringMVC的各组件中,处理器映射器、处理器适配器、视图解析器称为SpringMVC的三大组件。
当在springConfig.xml配置文件中配置<mvc:annotation-driven/>时,会自动创建和加载RequestMappingHandlerMapping(处理器映射器)、RequestMappingHandlerAdapter(处理器适配器),因此不需要再手动创建和配置这两个组件。

三 SpringMVC注解

@RequestMapping
作用:响应指定的请求
范围:类、方法
属性:
value、name:用于指定响应的请求路径
method:限制请求的方式
params:限制请求中必须包含的参数,参数应满足的条件;
headers:限制请求头中必须包含的字段,字段应满足的条件;

@Controller
@RequestMapping("/test")
public class HelloController {

    @RequestMapping(
            value/path="/requestMappingTest",
            method = {RequestMethod.GET,RequestMethod.POST},
            params = {"name","age=10"},
            headers = {"from","accept"}
    )
    public String testRequestMapping(){
        return "success";
    }
}

四 请求参数绑定:获取请求中的参数

浏览器通过表单提交数据,参数都以键值对形式存在。username=haha&password=13

RequestMapping修饰的方法,如果参数列表中的参数名和提交的表单中的键相同(区分大小写),SpringMVC会自动将值赋给参数,这就是请求参数绑定。
【底层是通过反射的方式获取方法的参数,再将表单中的值赋给参数】

支持的参数数据类型:
基本数据类型和字符串类型
集合数据类型(List、Map等)
实体类型(JavaBean):实体类型的成员变量又可以为实体类型、集合类型

基本数据类型和字符串:

//    http://localhost:8080/test/requestMappingTest?username=zs&age=10
    @RequestMapping("/bindBaseTest")
    public String bindBaseTest(String name,int age){
        System.out.println(name+":"+age);
        return "success";
    }

集合数据类型:
@RequestParam:当请求参数是集合类型时,才必须要这个注解。不然使用自动参数绑定就够了。

List测试

<%@ page contentType ="text/html;charset=utf-8" language="java"%>
<html>
<body>
<form action="/bindListTest" method="post">
    姓名List:<input type="text" name="names"/><br/>
    年龄List:<input type="text" name="ages"/><br/>
    <input type="submit" value="提交">
</form>
</body>
</html>
    @RequestMapping("bindListTest")
    public String bindCollTest(@RequestParam List<String> names, @RequestParam List<Integer> ages){
        System.out.println(names);
        System.out.println(ages);
        return "success";
    }

浏览器表单:
在这里插入图片描述

后端输出:
在这里插入图片描述
Map测试:

<%@ page contentType ="text/html;charset=utf-8" language="java"%>
<html>
<body>
<form action="/bindMapTest" method="post">
    姓名:<input type="text" name="name"/><br/>
    年龄:<input type="text" name="age"/><br/>
    <input type="submit" value="提交">
</form>
</body>
</html>
    @RequestMapping("bindMapTest")
    public String bindCollTest(@RequestParam Map<String,Integer> nameAge){
        System.out.println(nameAge);
        return "success";
    }

在这里插入图片描述
在这里插入图片描述
注意:
必须要使用@RequestParam,不然无法解析数据。

https://blog.csdn.net/cqboy1991/article/details/45150189

实体类型:
当实体类型中的属性依然为实体类型、集合类型时,这时候要参数绑定,主要工作是在jsp页面的代码中。jsp页面的代码中,必须知道表单中哪些数据用于进一步构成实体类型、集合类型。也就是说写jsp页面时必须知道后端接收的controller中参数的详细情况,只要接口文档确定,这个没有问题。

简单Bean:

<%@ page contentType ="text/html;charset=utf-8" language="java"%>
<html>
<body>
<form action="/bindBeanTest" method="post">
    姓名:<input type="text" name="name"/><br/>
    年龄:<input type="text" name="age"/><br/>
    <input type="submit" value="提交">
</form>
</body>
</html>
public class User {
    private String name;
    private int age;

	// getter、setter、toString 略
}
    @RequestMapping("bindBeanTest")
    public String bindBeanTest(User user){
        System.out.println(user);
        return "success";
    }

在这里插入图片描述
在这里插入图片描述
复杂Bean:

<%@ page contentType ="text/html;charset=utf-8" language="java"%>
<html>
<body>
<form action="/bindBeanTest" method="post">
    姓名:<input type="text" name="name"/><br/>
    年龄:<input type="text" name="age"/><br/>

    分数List:<input type="text" name="scores"/><br/>
    数学分数:<input type="text" name="scoresDetail['math']"/><br/>
    音乐分数:<input type="text" name="scoresDetail['music']"/><br/>

    同学名称1<input type="text" name="classmates[0].name"/><br/>
    同学年龄1<input type="text" name="classmates[0].age"/><br/>
    同学名称2<input type="text" name="classmates[1].name"/><br/>
    同学年龄2<input type="text" name="classmates[1].age"/><br/>

    朋友1名称:<input type="text" name="friendsDetail['fri1'].name"/><br/>
    朋友1年龄:<input type="text" name="friendsDetail['fri1'].age"/><br/>
    朋友2名称:<input type="text" name="friendsDetail['fri2'].name"/><br/>
    朋友2年龄:<input type="text" name="friendsDetail['fri2'].age"/><br/>
    <input type="submit" value="提交">
</form>
</body>
</html>
public class User {
    private String name;
    private int age;
    private List<Integer> scores;
    private Map<String,Integer> scoresDetail;
    private List<User> classmates;
    private Map<String,User> friendsDetail;
	// getter、setter、toString 略
}
    @RequestMapping("bindBeanTest")
    public String bindBeanTest(User user){
        System.out.println(user);
        return "success";
    }

在这里插入图片描述
在这里插入图片描述
实体类型时作为List、Map的属性,不需要用@RequestParam了。

可以看到,参数绑定中,工作量都集中在jsp的编写上。

既然,基本上都能进行参数绑定,那@RequestParam的作用是什么?仅仅是加强了对List、Map的支持吗?
https://blog.csdn.net/w2222288/article/details/45272527
https://blog.csdn.net/cqboy1991/article/details/45150189

自定义类型转换器:
上面参数绑定过程中有一个问题,前端页面向后端发送的所有数据都是字符串,但是参数绑定中能直接赋值给int变量,如何转换的?SpringMVC框架自动调用类型转换器实现的。
框架已经实现了常见类型的转换,但一些情景中需要自定义,如日期格式,前端可能有多种方式表示日期,2020-10-29,2020/10/29。后端要将其转为Date类型。【SpringMVC自带的是2020/10/29转为Date】

自定义类型转换器步骤:
1.创建自定义类型转换器类;
2.注册到SpringMVC框架的类型转换服务中;
3.启动自定义类型转换器;

创建自定义类型转换器

public class StringToDate implements Converter<String, Date> {
    @Override
    public Date convert(String source){
        if(source == null){
            throw new RuntimeException("数据为空");
        }
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        try {
            return dateFormat.parse(source);
        }catch (ParseException e){
            throw new RuntimeException("数据类型转换错误");
        }
    }
}

注册自定义类型转换器:项目配置文件springConfig.xml中配置

    <!-- 配置自定义类型转换器:点进ConversionServiceFactoryBean可查看源码-->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <!-- 将自定义类型转换器注册到conversionService中-->
        <!-- conversionService的converters属性中注册了各种类型转换器-->
        <property name="converters">
            <set>
                <bean class="com.test.StringToDate"></bean>
            </set>
        </property>
    </bean>

    <!-- 开启对SpringMVC框架注解的支持: 默认开启组件对视图解析器、处理器映射器、适配器-->
    <!-- 类型转换器需要手动开启生效-->
    <mvc:annotation-driven conversion-service="conversionService"/>

controller中获取Servlet原生的API:
@RequestMapping修饰的函数中获取request、response对象,直接在参数列表中指明,就可以获取request、response对象了。
个人理解:由于servletTest方法是SpringMVC框架自动调用的,SprngMVC会自动传入需要的参数。

    @RequestMapping("servletTest")
    public String servletTest(HttpServletRequest request, HttpServletResponse response){
        System.out.println(request);

        HttpSession session = request.getSession();
        System.out.println(session);

        ServletContext context = session.getServletContext();
        System.out.println(context);

        System.out.println(response);
        
        return "success";
    }

常用注解:

@RequestParam
这个注解和参数绑定的功能有重合,除了前面参数绑定中给出的传集合类型的情况下,需要使用该注解外。其他情况下,只有这个需求是要使用:
前端将变量命名为A,后端想要命名为B,这样无法直接用变量B接收变量A的值,这时就用到该注解,在该注解的value属性中声明前端使用的变量名为A,这样就把前端变量名A和后端变量名B对应上了。
感觉很鸡肋,应该后端还是要写明前端所采用的变量名,只不过换到写在@RequestParam的参数中了。

    @RequestMapping("requestParamTest")
    public String requestParamTest(int A){
        System.out.println(A);
        return "success";
    }

    @RequestMapping("requestParamTest")
    public String requestParamTest(@RequestParam("A") int B){
        System.out.println(B);
        return "success";
    }

两种方法都能获取前端传来的变量A的值,一种是直接参数绑定,一种是使用@RequestParam

@RequestBody:
用于获取请求体内容,使用得到的是"key=value&key=value…"结构的字符串数据。在前后端传json数据时情况下常用。
get请求方式不适用:因为get请求没有请求体,所有参数都是在链接中了

自动解析请求体中的json字符串,进行参数绑定;参数为字符串就直接得到字符串了,为对象就能自动解析。不加该注解作为body变量进行参数绑定。

    @RequestMapping("requestBodyTest")
    public String requestBodyTest(@RequestBody String body){
        System.out.println(body);
        return "success";
    }

    @RequestMapping("requestBodyTest")
    public String requestBodyTest(String body){
        System.out.println(body);
        return "success";
    }

如果不加@RequestBody注解,表示从前端传来的参数(get或post方式)中解析名称为body的变量

@PathVariable
用于绑定url中的占位符,是为了实现RESTful风格的接口

原来方式:controller中方法通过路径来区分
@Controller
UserController{
    @RequestMapping("/user/save")
    public void save(User user){
        ...
    }

    @RequestMapping(value = "/user", method = RequestMethod.DELETE)
    public void delete(User user){
        ...
    }
    @RequestMapping("/user/update")
    public void update(User user){
        ...
    }

    @RequestMapping("/user/findAll")
    public void findAll(){
        ...
    }
}

RESTful风格:方法对应的请求路径可以完全相同,结合请求的方式来确定要执行的方法
@Controller
UserController{
    @RequestMapping(value = "/user",method = RequestMethod.POST)
    public void save(User user){
        ...
    }

    @RequestMapping(value = "/user", method = RequestMethod.PUT)
    public void update(User user){
        ...
    }

    @RequestMapping(value = "/user", method = RequestMethod.DELETE)
    public void delete(User user){
        ...
    }

    @RequestMapping(value = "/user", method = RequestMethod.GET)
    public void findAll(User user){
        ...
    }
}

上面Restful风格存在一个问题,请求的方式是有限的,如果有两个查询方法,照理说都要用Get请求方式,那后端如何区分?
所以还是要基于请求路径区分,这时就用到@PathVariable注解了。

    @RequestMapping(value = "/user", method = RequestMethod.GET)
    public void findAll(User user){
        ...
    }

    @RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
    public void findById(@PathVariable(value="id") String id){
        ...
    }

路径中使用参数是Restful风格的需要,并不是随意把路径作为参数识别就是Restful风格了,不要本末倒置

Restful风格的优点:
1.结构清晰
2.符合标准
3.易于理解
4.扩展方便
另外,由于请求路径数量变少了,可以减少浏览器的缓存

过滤器:
1.上面讲Restful风格其实还存在一个问题,浏览器只能发送GET、POST请求,PUT、DELETE等方式不支持,但是Restful风格确实要使用这些请求方式。
所以,后端必须在controller处理之前,修改部分请求的请求方式。这符合拦截器 过滤器的作用时机。

第一步.web.xml中配置过滤器

<!-- 配置转换隐藏请求方式的过滤器-->
  <filter>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

第二步:jsp页面指明要发送何种请求
jsp必须以post方式发送请求,jsp中的表单使用隐藏域,在隐藏域中指明后端应该转换到的请求方式。

<%@ page contentType ="text/html;charset=utf-8" language="java"%>
<html>
<body>
<form action="/RestfulTest" method="post">
    姓名:<input type="text" name="name"/><br/>
    年龄:<input type="text" name="age"/><br/>
    <input type="hidden" name="_method" value="PUT">
    <input type="submit" value="提交">
</form>
</body>
</html>

视频中说,以上在模拟请求的过程中采用的方式。

2.可以解决中文乱码
get请求不会导致中文乱码,post请求会导致
可以在每个controller中通过request.setCharacterEncoding(“UTF-8”)来解决,也可能通过设置过滤器统一解决

在web.xml中配置字符编码的过滤器

  <!-- 配置解决中文乱码的过滤器-->
  <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>

@RequestHeader
用于获取请求头中某个字段的值,@RequestHeader后面必须要指明获取请求头中的哪个字段,不能直接获取整个请求头。

    @RequestMapping("/requestHeaderTest")
    public String requestHeaderTest(@RequestHeader("user-agent") String userAgent){
        System.out.println(header);
        return "success";
    }

@CookieValue
用于获取Cookie中某个值
在这里插入图片描述

    @RequestMapping("/cookieValueTest")
    public String cookieValueTest(@CookieValue("JSESSIONID") String sessionId){
        System.out.println(sessionId);
        return "success";
    }

@ModelAttribute
可以作用在方法和参数上
该注解修饰的方法,会在controller中所有其他方法(如:@RequestMapping修饰的方法)执行前被执行。
适用场景:User有name、age、birthday三个字段,但是前端更新只能提交了name、age两个字段,也就是前端给的birthday字段值为null。如果此时直接调用@RequestMapping修饰的update方法更新,则birthday会更新为null。如果需求为:请求中未提供的属性采用数据库中现有的属性,则可以先在update方法执行前,用@ModelAttribute修饰的方法判断前端参数的完整性,并根据name查找当前数据库中User的birthday,然后补充完整User,再由update响应请求。
@ModelAttribute将处理后的参数值传给update有两种方式:直接作为返回值、加入Map。

可以理解为@ModelAttribute对应于Request对象中的数据字段,被修饰的方法用于预处理数据字段值并更新,被修饰的变量用于访问Request对象中的指定名称的数据字段

有返回值的情况
	// 假设前端提交的Usesr中缺少name字段
    @RequestMapping("/modelAttributeTest")
    public String test(User user){
        System.out.println(user);
        return "success";
    }

    @ModelAttribute
    public User modelAttributeTest(User user){
        if (user.getName() == null){
            user.setName("zs");
        }
        return user;
    }

没有返回值的情况
    @RequestMapping("/modelAttributeTest")
    public String test(@ModelAttribute("myUser") User user){
        System.out.println(user);
        return "success";
    }

    @ModelAttribute
    public void modelAttributeTest(User user,Map<String,User> map){
        if (user.getName() == null){
            user.setName("zs");
            map.put("myUser",user);
        }
    }

@SessionAttribute
作用在类上,用于多次执行控制器方法间的参数共享。
session会话域中可能会发送多次请求,该注解可实现请求之间参数共享。
session域中数据存入、取出、删除
【Model是接口,ModelMap是实现类】

<%@ page contentType ="text/html;charset=utf-8" language="java" isELIgnored="false" %>
<html>
<body>
    <a href="/setSessionAttributeTest">setSessionAttributeTest</a>
    <a href="/getSessionAttributeTest">getSessionAttributeTest</a>
    <a href="/deleteSessionAttributeTest">deleteSessionAttributeTest</a>

    <%-- 需要设置isELIgnored="false"--%>
    ${ requestScope}
    ${ sessionScope}

</form>
</body>
</html>
@Controller
@SessionAttributes({"msg"})
public class HelloController {
//    向session域中存值
    @RequestMapping("/setSessionAttributeTest")
    public String setSessionAttributeTest(Model model){
        System.out.println(model);
        model.addAttribute("msg","sharedSessionAttribute")
        return "success";
    }

//    从session域中取值
    @RequestMapping("/getSessionAttributeTest")
    public String getSessionAttributeTest(ModelMap modelMap){
        System.out.println(modelMap);
        String msg = (String) modelMap.get("msg");
        System.out.println(msg);
        return "success";
    }

//    删除session域中的值
    @RequestMapping("/deleteSessionAttributeTest")
    public String deleteSessionAttributeTest(SessionStatus status){
        System.out.println(status);
        status.setComplete();
        return "success";
    }
}
存入Request域

方法一:直接操作Request对象
    @RequestMapping("/requestAttributeTest")
    public String requestAttributeTest1(HttpServletRequest request){
        System.out.println(request);
        request.setAttribute("msg","sharedSessionAttribute");
        return "success";
    }
方法二:存入model,由SpringMVC框架实现存入Request域
    @RequestMapping("/requestAttributeTest2")
    public String requestAttributeTest2(Model model){
        System.out.println(model);
        model.addAttribute("msg","sharedSessionAttribute");
        return "success";
    }

补充:SpringMVC提供的将数据存入request域的方法。
…方法参数中使用Model参数…
本来可以先直接获取Requeset对象,然后存入Request对象中,但是这样与ServletAPI耦合太严重。所以SpringMVC提供了上述方法,由SpringMVC将数据存入Request域。
Request域、Session域中的数据可在jsp中使用。Session域中的数据可在多个@RequestMapping修饰的方法间共享。
Map中貌似既有Request域也有Session域的内容。

注意:不要把jsp当作一个HTML页面,当作一个Java程序才更加合适。jsp页面中是可以访问到各种变量的。【jsp本质上就是一个servlet,是java代码嵌入在模板中】【话说后端有什么不是servlet吗?controller也是servlet吧,filter之类的组件不是servlet吗?这是JavaWeb中的吗?】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值