笔记基于以下教程,包括: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中的吗?】