摘要
SpringMVC表现层这块的东西,倒是不难使用,直接上手就行。
但是经常会有东西不理解怎么实现的,可能是封装的太好了,会用却不理解,然后就有去翻源码的操作,所以打算系统学习一下。
正文
例子中很多都是接口形式的,虽然案例中使用的是html发送请求的方式,但是还是更推荐使用postman来调试,会方便许多。
一、基本概念 1.1 三层架构 我们的开发模式,一般都是基于两种形式,一种是C/S架构,也就是客户端/服务器;另一种是B/S架构,也就是浏览器/服务器。
在JavaEE开发中,几乎全都是基于B/S架构的开发。在B/S架构中,系统标准的三层架构包括:表现层、业务层、持久层。
表现层:如SpringMVC。负责接收客户端的请求、向客户端响应结果。表现层包括展示层和控制层。 业务层:如Spring。也就是service层,负责业务逻辑处理,表现层依赖业务层,业务层并不依赖表现层。 持久层:如Mybatis、Hibernate。
展开
1.2 MVC模型 MVC全名是Model View Controller,是模型-视图-控制器的缩写,是一种用于设计创建web应用程序表现层的模式。MVC中每个部分各司其职
Model模型:通常指的是数据模型。一般情况下用于封装数据。 View视图:如html。展示数据,视图通常是依据数据模型来创建的。 Controller控制器:应用程序中处理用户交互的部分。作用一般就是处理程序逻辑的。 1.3 SpringMVC SpringMVC是一种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,是目前最主流的MVC框架之一。同样的MVC框架还有structs2。支持RestFul编程风格。
展开
优势
清晰的角色划分前端控制器DispatcherServlet 请求到处理器映射HandlerMapping 处理器适配器HandlerAdapter 视图解析器ViewResolver 处理器或页面控制器Controller 验证器Validator 命令对象Command(请求参数绑定到的对象就叫命令对象) 表单对象FormObject(提供给表单展示和提交到的对象叫表单对象) 命令对象就是一个pojo,直接就能作为业务对象 SpringMVC基于组件的方式执行流程 1.4 restful编程
展开
对比这张图里,就能大概了解restful是个啥意思了。
传统的编程中,控制器里面,save、findAll、update会支持各种请求方法,创建三个接口。
restful编程中,控制器里面只需要提供一个接口,接口按照不同的请求方式执行不同的操作。
restful编程参考RESTful API 设计指南 - 阮一峰的网络日志 ,如果你用了屏蔽广告插件导致内容无法显示,直接将其域名的js权限禁用掉就ok。
对于资源的具体操作类型,由HTTP动词表示。
常用的HTTP动词有下面五个(括号里是对应的SQL命令)。
GET(SELECT):从服务器取出资源(一项或多项)。 POST(CREATE):在服务器新建一个资源。 PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。 PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。 DELETE(DELETE):从服务器删除资源。 还有两个不常用的HTTP动词。
HEAD:获取资源的元数据。 OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。 下面是一些例子。
GET /zoos:列出所有动物园 POST /zoos:新建一个动物园 GET /zoos/ID:获取某个指定动物园的信息 PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息) PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息) DELETE /zoos/ID:删除某个动物园 GET /zoos/ID/animals:列出某个指定动物园的所有动物 DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物 二、入门 2.1 实现 需求
index.jsp发送请求 转发 到success.jsp成功页面步骤
搭建开发环境:使用maven提供的骨架搭建webapp 编写程序 pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<?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" >
<modelVersion> 4.0.0</modelVersion>
<groupId> top.meethigher</groupId>
<artifactId> SpringMvc</artifactId>
<version> 1.0</version>
<packaging> war</packaging>
<name> SpringMvc Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url> http://www.example.com</url>
<!-- 版本锁定 -->
<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-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>
</dependencies>
<build>
<finalName> SpringMvc</finalName>
<pluginManagement> <!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId> maven-clean-plugin</artifactId>
<version> 3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId> maven-resources-plugin</artifactId>
<version> 3.0.2</version>
</plugin>
<plugin>
<artifactId> maven-compiler-plugin</artifactId>
<version> 3.8.0</version>
</plugin>
<plugin>
<artifactId> maven-surefire-plugin</artifactId>
<version> 2.22.1</version>
</plugin>
<plugin>
<artifactId> maven-war-plugin</artifactId>
<version> 3.2.2</version>
</plugin>
<plugin>
<artifactId> maven-install-plugin</artifactId>
<version> 2.5.2</version>
</plugin>
<plugin>
<artifactId> maven-deploy-plugin</artifactId>
<version> 2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
web.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!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>
<!--前端控制器-->
<servlet>
<servlet-name> dispacherServlet</servlet-name>
<servlet-class> org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name> contextConfigLocation</param-name>
<param-value> classpath:springmvc.xml</param-value>
</init-param>
<!--不配置dispatcherServlet只会在第一次收到请求启动,配置为项目启动时启动。当值为0或者大于0时,表示容器在应用启动时就加载这个servlet;当是一个负数时或者没有指定时,则指示容器在该servlet被请求时才加载。-->
<load-on-startup> 1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name> dispacherServlet</servlet-name>
<url-pattern> /</url-pattern>
</servlet-mapping>
</web-app>
springmvc.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://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= "top.meethigher" />
<!--配置spring开启注解mvc的支持-->
<mvc:annotation-driven/>
<!-- 配置视图解析器 -->
<bean id= "viewResolver"
class= "org.springframework.web.servlet.view.InternalResourceViewResolver" >
<property name= "prefix" value= "/WEB-INF/pages/" ></property>
<property name= "suffix" value= ".jsp" ></property>
</bean>
</beans>
index.jsp
1
2
3
4
5
6
7
8
9
10
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门程序</h3>
<a href="/hello">入门程序</a>
</body>
</html>
success.jsp
1
2
3
4
5
6
7
8
9
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门成功</h3>
</body>
</html>
HelloController.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Controller
public class HelloController {
/**
* 修改默认构造方法,验证加载顺序
*/
public HelloController () {
System . out . println ( "启动" );
}
@RequestMapping ( "/hello" )
public String sayHello (){
System . out . println ( "Hello MVC" );
return "success" ;
}
}
访问的hello,实际是转发请求到了success.jsp
2.2 原理
展开
由于配置了dispatcherServlet为项目启动时就进行加载,所以像springmvc.xml,以及创建扫描的类和视图解析器的对象。
可以在添加了注解并且要进行扫描的类中,在默认构造方法中打印日志来验证,不同的配置的执行顺序。
dispatcherServlet主要体现在他的控制作用,客户端的请求过来,首先被dispatcherServlet捕获,然后将请求转发到对应的控制器中获取到返回值,根据这个返回值,通过视图解析器,解析到对应的结果视图。将返回内容返给客户端。
2.3 组件详解
展开
DispatcherServlet:前端控制器
DispatcherServlet是整个流程控制的中心,由他来调用其他组件处理用户的请求,同时,也降低了组件之间的耦合性。
HandlerMapping:处理器映射器
HandlerMapping负责根据用户请求找到请求适配器HandlerAdapter。
HandlerAdapter:处理器适配器
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用。通过扩展适配器可以对更多类型的处理器进行执行。
Handler:处理器
开发中要编写的具体业务控制器。由DispatcherServlet把用户请求转发到Handler,由Handler对具体的用户进行请求处理。
ViewResolver:视图解析器
View Resolver负责将处理结果生成view视图。View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。
View:视图
SpringMVC提供了很多view视图的支持,像jstlView、freemarkerview、pdfView。
2.4 RequestMapping
展开
通过阅读源码可知,@RequestMapping既可以放在类上也可以放在方法上。并且其中的value与path作用是相同的。
如果只有一个属性需要赋值,并且属性的名称是value ,则value可以省略
如果在类上加了@RequestMapping注解,并且配置了value,那么,方法中所有的通过@RequestMapping配置的路径,都在类的value的路径之下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Controller
@RequestMapping ( "/hh" )
public class HelloController {
/**
* 修改默认构造方法,验证加载顺序
*/
public HelloController () {
System . out . println ( "启动" );
}
@RequestMapping ( value = "/hello" , method = { RequestMethod . DELETE , RequestMethod . GET }, params = { "name" , "age" }, headers = "aaa" )
public String sayHello (){
System . out . println ( "Hello MVC" );
return "success" ;
}
}
上面代码,访问sayHello方法时,就需要通过/hh/hello来访问。
method属性表示访问的请求方式。上述代码只能通过Delete、Get请求访问。
params属性用于指定限制请求参数的条件,必传的名称可以放入到params里面。上述代码必须携带name、age参数。
headers属性用于限制请求头的条件,必传的名称放入headers里面。
三、参数绑定 参数绑定通俗点说,就是获取参数。类似于Servlet通过getParameter获取参数。
基本参数 如果接收的参数是基本类型,可以直接通过在controller中写方法,就能自动接收了。
发送请求
1
< a href = "hh/param?name=hh&age=20" > 入门程序</ a >
获取参数
1
2
3
4
5
6
7
8
9
@Controller
@RequestMapping ( "/hh" )
public class HelloController {
@RequestMapping ( value = "/param" )
public String getParam ( String name , String age ){
System . out . println ( "name=" + name + ",age=" + age );
return "success" ;
}
}
实体参数 属性为基本或实体类型 如果是实体参数内部都是基本属性,可以直接在控制器方法中写对应实体,直接接收。
如果是实体参数内部嵌套了实体属性,就需要在发送时用对象属性.属性来发送请求,控制器那边直接写实体接收即可。
发送请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门程序</h3>
<a href="hh/param?name=hh&age=20">入门程序</a>
<h3>造钱</h3>
<form action="/hh/money" method="post">
<input name="money" placeholder="钱">
<button type="submit">submit</button>
</form>
<h3>造人</h3>
<form action="/hh/person" method="post">
<input name="name" placeholder="名">
<input name="age" placeholder="年龄">
<input name="money.money" placeholder="钱">
<button type="submit">submit</button>
</form>
</body>
</html>
控制器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Controller
@RequestMapping ( "/hh" )
public class HelloController {
/**
* 实体类
* @param money
* @return
*/
@RequestMapping ( value = "/money" )
public String getMoney ( Money money ){
System . out . println ( money );
return "success" ;
}
/**
* 实体类嵌套实体类
* @param person
* @return
*/
@RequestMapping ( value = "/person" )
public String getPerson ( Person person ){
System . out . println ( person );
return "success" ;
}
}
在post请求时,会出现后端获取中文出现乱码的情况。
如果是在Servlet中时,我们需要通过request.setCharacterEncoding("utf-8")来解决。
在Spring中,提供了类似的方法,需要在配置文件中配置过滤器
web.xml配置如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!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>
<!--前端控制器-->
<servlet>
<servlet-name> dispacherServlet</servlet-name>
<servlet-class> org.springframework.web.servlet.DispatcherServlet</servlet-class>
<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> dispacherServlet</servlet-name>
<url-pattern> /</url-pattern>
</servlet-mapping>
<!--配置解决中文乱码的过滤器-->
<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>
</web-app>
通过阅读filter-class源码,我们可以知道其实本质上,它也是走的request.setCharacterEncoding这个方式。
展开
属性为集合类型 直接看例子吧。
请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<%--
Created by IntelliJ IDEA.
User: meethigher
Date: 2021/8/22
Time: 21:29
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>List与Map</h3>
<form action="/hh/people" method="post">
<input name="personList[0].name" placeholder="名"/>
<input name="personList[0].age" placeholder="年龄"/>
<input name="personList[0].money.money" placeholder="钱"/>
<input name="personList[1].name" placeholder="名"/>
<input name="personList[1].age" placeholder="年龄">
<input name="personList[1].money.money" placeholder="钱">
<input name="personMap['first'].name" placeholder="名"/>
<input name="personMap['first'].age" placeholder="年龄"/>
<input name="personMap['first'].money.money" placeholder="钱"/>
<input name="personMap['second'].name" placeholder="名"/>
<input name="personMap['second'].age" placeholder="年龄">
<input name="personMap['second'].money.money" placeholder="钱">
<button type="submit">submit</button>
</form>
</body>
</html>
控制器
1
2
3
4
5
6
7
8
9
10
@Controller
@RequestMapping ( "/hh" )
public class HelloController {
@RequestMapping ( value = "/people" )
public String getList ( People people ){
System . out . println ( people );
return "success" ;
}
}
自定义类型转换器 Spring提供的转换器都实现了Convertor这个接口,所以如果我们要实现自定义类型转换器的话,也需要实现该接口。
展开
Convertor的两个泛型,前面指的是源类型、后面指的是目标类型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class StringToDateConverter implements Converter < String , Date > {
@Override
public Date convert ( String source ) {
if ( ObjectUtils . isEmpty ( source )) {
throw new RuntimeException ( "必须传入数据!" );
}
SimpleDateFormat sdf = new SimpleDateFormat ( "yyyy-MM-dd" );
try {
return sdf . parse ( source );
} catch ( ParseException e ) {
throw new RuntimeException ( "必须传入数据!格式yyyy-MM-dd" );
}
}
}
springmvc.xml配置添加自定义转换器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://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= "top.meethigher" />
<!-- 配置视图解析器 -->
<bean id= "viewResolver"
class= "org.springframework.web.servlet.view.InternalResourceViewResolver" >
<property name= "prefix" value= "/WEB-INF/pages/" ></property>
<property name= "suffix" value= ".jsp" ></property>
</bean>
<!--配置自定义类型转换器-->
<bean id= "customConversionService" class= "org.springframework.context.support.ConversionServiceFactoryBean" >
<property name= "converters" >
<set>
<bean class= "top.meethigher.controller.StringToDateConverter" />
</set>
</property>
</bean>
<!--配置spring开启注解mvc的支持 并支持自定义类型转换器-->
<mvc:annotation-driven conversion-service= "customConversionService" />
</beans>
发送请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>创建一只狗</h3>
<form action="/hh/dog" method="post">
<input name="name" placeholder="名">
<input name="birth" placeholder="生日">
<button type="submit">submit</button>
</form>
</body>
</html>
控制器
1
2
3
4
5
6
7
8
9
@Controller
@RequestMapping ( "/hh" )
public class HelloController {
@RequestMapping ( value = "/dog" )
public String getDog ( Dog dog ) {
System . out . println ( dog );
return "success" ;
}
}
获取Servlet原生API 如果想要获取servlet的request,那就直接在控制器方法中加HttpServletRequest。
如果想要获取servlet的response,那就直接在控制器方法中加HttpServletResponse。
发送请求
1
<a href="/hh/api">servletAPI</a>
控制器
1
2
3
4
5
6
7
8
9
10
11
12
@Controller
@RequestMapping ( "/hh" )
public class HelloController {
@RequestMapping ( value = "/api" )
public String getApi ( HttpServletRequest request , HttpServletResponse response ) {
System . out . println ( request );
System . out . println ( response );
System . out . println ( request . getSession ());
System . out . println ( request . getSession (). getServletContext ());
return "success" ;
}
}
四、常用注解 4.1 RequestParam 作用
把请求中的指定参数,给控制器方法中参数赋值
属性
value:请求的参数名称 required:请求参数中此参数是否必传。默认值true 请求
1
<a href="/testRequestParam?username=ccc">requestParam</a>
控制器
1
2
3
4
5
6
7
8
9
@Controller
public class AnnotationController {
@RequestMapping ( "/testRequestParam" )
public String testRequestParam ( @RequestParam ( value = "username" ) String username1 ) {
System . out . println ( username1 );
return "success" ;
}
}
如果不加@RequestParam,那么调用该接口时,没有对应的username属性来接收内容,输出为空。
如果加了@RequestParam,里面默认的required=true,那么调用该接口时,如果传值不对,会报错。
4.2 RequestBody 作用
get请求方式不适用。
用于获取请求体内容。直接使用,获取到的字符串是key=value&key=value的结构的数据。
属性
required:是否必须有请求体,默认为true 请求
1
2
3
4
5
6
<form action="/testRequestBody" method="post">
<input name="name" placeholder="名">
<input name="age" placeholder="年龄">
<input name="money.money" placeholder="钱">
<button type="submit">submit</button>
</form>
控制器
1
2
3
4
5
6
7
8
@Controller
public class AnnotationController {
@RequestMapping ( "/testRequestBody" )
public String testRequestBody ( @RequestBody String body ) {
System . out . println ( body );
return "success" ;
}
}
4.3 PathVariable @PathVariable接收两个参数
作用
绑定url中的占位符。例如/findById/{id},这个{id}就是url中的占位符。
url支持占位符是spring3.0之后加入的,是springmvc支持rest风格url的一个重要标志。参考1.4 。
属性
value:url中占位符名称 required:是否必须提供占位符 发送请求
1
< a href = "/testPathVariable/ccc" > pathVariable</ a >
控制器
1
2
3
4
5
@RequestMapping ( "/testPathVariable/{id}" )
public String testPathVariable ( @PathVariable ( value = "id" ) String id ) {
System . out . println ( id );
return "success" ;
}
注意事项
因为form表单只支持get、post请求,所以如果想要使用restful的话,那么就需要用到别的请求方式。这边SpringMVC提供了HiddenHttpMethodFilter过滤器,参考文章Spring MVC过滤器-HiddenHttpMethodFilter - 一个坚果 - 博客园
作用
获取请求消息头
属性
value:提供消息头名称 required:是否必须有此消息头 没啥用,就是获取请求头,倒不如用Servlet原生api
1
2
3
4
5
6
@RequestMapping ( "/testPathVariable/{id}" )
public String testPathVariable ( @PathVariable ( value = "id" ) String id , @RequestHeader ( "User-Agent" ) String userAgent ) {
System . out . println ( id );
System . out . println ( userAgent );
return "success" ;
}
4.5 CookieValue 作用
获取指定名称cookie
属性
value:指定cookie名称 required:是否必须有该Cookie 没啥用,就是获取请求头,倒不如用Servlet原生api
1
2
3
4
5
6
7
@RequestMapping ( "/testPathVariable/{id}" )
public String testPathVariable ( @PathVariable ( value = "id" ) String id , @RequestHeader ( "User-Agent" ) String userAgent , @CookieValue ( "JSESSIONID" ) String session ) {
System . out . println ( id );
System . out . println ( userAgent );
System . out . println ( session );
return "success" ;
}
4.5 ModelAttribute 作用
放在方法上,表示当前方法会在控制器的方法执行前先执行 。它可以修饰没有返回值的方法,也可以修改有具体返回值的方法。 放在参数上,获取指定的参数给数据赋值。 应用场景
当前端的表单提交数据,无法获取和提交完整的数据时,可以通过@ModelAttribute通过数据库补全缺少的数据。比如,前端在执行变更时,只需要传递过来要变更的id,以及要修改的字段内容,后台通过@ModelAttribute来补全未变更的数据,之后直接保存对象到数据库里。 没有特定条件的@ModelAttribute会在所有控制器的方法执行前执行
如:
1
2
3
4
@ModelAttribute
public void showMsg (){
System . out . println ( "@ModelAttribute执行" );
}
如果想要让控制器的方法获取到@ModelAttribute返回的对象,有两种方式
法一:@ModelAttribute修饰的方法带有返回值
1
2
3
4
5
6
7
8
9
10
11
@RequestMapping ( "/testDog" )
public String testDog ( Dog dog ) {
System . out . println ( dog );
return "success" ;
}
@ModelAttribute
public Dog modelAttribute ( @RequestParam ( value = "username1" ) String username1 ) {
System . out . println ( "modelAttribute执行了" );
System . out . println ( username1 );
return new Dog ( "aaa" , new Date ());
}
上面这个例子,如果要访问testDog接口,会先访问modelAttribute方法,并且要求必传username1,然后再执行testDog方法。
如果传了username1,又传了Dog对象,那么username1就只是作为一个必传的入参了,优先级没有直接传入的Dog对象优先级高。
展开
展开
法二:@ModelAttribute修饰的方法不带返回值
1
2
3
4
5
6
7
8
9
10
11
@RequestMapping ( "/testDog" )
public String testDog ( @ModelAttribute ( "dog" ) Dog dog ) {
System . out . println ( dog );
return "success" ;
}
@ModelAttribute
public void modelAttribute ( @RequestParam ( value = "username1" ) String username1 , Map < String , Dog > map ) {
System . out . println ( "modelAttribute执行了" );
System . out . println ( username1 );
map . put ( "dog" , new Dog ( "aaa" , new Date ()));
}
最终的效果其实跟法一是一样的。并没有因为换了方法优先级就高了之类。
4.6 SessionAttribute 作用
用于多次执行控制器方法间的参数在Session间共享。
属性
value:存入的属性名称 type:存入的数据类型 success.jsp
1
2
3
4
5
6
7
8
9
10
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门成功</h3>
${requestScope.msg}
</body>
</html>
Controller中方法
1
2
3
4
5
6
7
@RequestMapping ( "/testSession" )
public String testSession ( Model model ){
System . out . println ( "测试SessionAttributes注解" );
//底层会给存储到requestScope对象中,可以通过跳转后的jsp来获取
model . addAttribute ( "msg" , "彩麟yyds" );
return "success" ;
}
Model是存储在RequestScope中的,如果想要存到SessionScope,需要通过@SessionAttributes。
查看@SessionAttributes源码,可知该注解只能作用于类上。
1
2
3
4
5
6
7
8
9
10
11
12
13
@Target ({ ElementType . TYPE })
@Retention ( RetentionPolicy . RUNTIME )
@Inherited
@Documented
public @interface SessionAttributes {
@AliasFor ( "names" )
String [] value () default {};
@AliasFor ( "value" )
String [] names () default {};
Class <?>[] types () default {};
}
通过@SessionAttributes将RequestScope中的msg存入到SessionScope中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Controller
@SessionAttributes ( value = "msg" )
public class AnnotationController {
@RequestMapping ( "/testSession" )
public String testSession ( Model model ){
System . out . println ( "测试SessionAttributes注解" );
//底层会给存储到requestScope对象中,可以通过跳转后的jsp来获取
model . addAttribute ( "msg" , "彩麟yyds" );
return "success" ;
}
@RequestMapping ( "/getMsg" )
public String getMsg ( ModelMap modelMap ){
//ModelMap用于获取SessionScope中的内容
System . out . println ( modelMap . get ( "msg" ));
return "success" ;
}
@RequestMapping ( "/delMsg" )
public String delMsg ( SessionStatus status ){
//结束当前会话,清除Session中内容
status . setComplete ();
return "success" ;
}
}
4.7 ResponseBody @ResponseBody作用于方法上,表示该方法的返回结果直接写入到响应中,一般用于前端异步获取数据时,也就是接口。
@RestController=@Controller+@ResponseBody
@Controller可以返回到指定的jsp、html等模板引擎页面
springBoot的转发和重定向_anjunshuang-CSDN博客_springboot转发