一.请求-传递参数接收参数
在浏览器中访问不同的路径就是发送不同的请求,在发送请求时往往会进行参数传递。所以我们要学习如何传递参数到后端以及后端如何接收参数。
传递参数就是浏览器的queryString部分,或者用postman,我们不用关注,主要就是关注如何接收参数
1.接收单个参数
假设要接收的参数是一个String类型的并且键值对的key为name。则如下进行接收
我们来用postman发送请求
注意:
当传递的参数是基本类型时,在发送请求时参数必须传递,否则会报错
为什么?因为基本类型不能被传递为null空值,导致其没有默认值,所以会报错。而对于引用类型,它没有被赋值时就会默认是空值,所以就会在没有传参时返回null,就不会报错。比如String类型,若没有传参,默认值就是null
所以以后传递基本类型时,一般建议使用包装类
2.接收多个参数
注意,m2方法的参数名称,必须与请求中的key对应。顺序可以不对应,但是名字要相同,请求中是age,后端方法中就也是age,而不能是age1
也就是说,当有多个参数时,前后端进行参数匹配,是以参数的名称进行匹配的,因此参数的位置时不影响后端获取参数的结果的
3.接收对象
如果要传递的信息比较多时,后端的方法声明中就要有多个参数,而且后续如果又想加一些参数,就得再重写方法声明。这时候,我们就可以选则将这些参数放到一个类中,封装成一个对象。Spring MVC也可以自动实现对对象的赋值
如下:我们准备一个User类,通过请求来传递user对象中各个成员变量的值,如下:
注意:
在以对象的形式进行参数接收时,如果某个参数没有传递,即使是基本类型,也不会报错!!因为对于一个对象,他的成员变量是有默认值的!!
4.后端参数重命名
某些情况下,前端参数的key不是我们想要定义的key,这是就要对该参数进行重命名,如下:
注意:
若此时没有传递该参数,就会报错,即使是包装类型
控制台也抛出了Servlet请求参数缺少异常
也就是说,当对参数进行重命名后,该参数就变成了一个必传参数
非必传参数设置
如果这个重命名参数是一个非必传参数,那我们该怎么做?首先来了解一下为啥它变成了一个必传参数,如下,看一下RequestParam这个注解
里面有一个required,默认是true,表示的含义就是该参数是一个必传参数
所以要想非必传。就要如下设置
只要一加required属性,前面的"date"就自动加上了value这个key
5.传递数组
示例如下:
数组传参的关键:请求的参数名要与形参数组名相同,且请求参数为多个
前端参数传递也可以使用如下形式
就是用逗号分隔
但注意,普通浏览器中的逗号需要进行urlencoded转码,只不过谷歌和postman可以自动转码
6.传递集合
注意,要在参数前面加一个@RequestParam注解,当没有加该注解时,默认是以数组形式接收
如果没有加@RequestParam,则会有下面的信息
报错为500,表示后端出错,然后我们就看控制台信息:
7.传递json格式数据
还是使用User类
注意,后端要在参数生命前面加一个@RequestBody注解,表示要在请求正文进行数据绑定,也就是说请求参数必须写在请求正文中,或者说后端只从请求正文中读取数据,而不会看url中的queryString
注意:如果前端json中的key重复了,最后赋值时是按最后一个key的value进行性赋值:
8.获取URL中的参数
这里是用到@PathVariable注解,这个注解的主要作用就是在请求的URL路径上进行数据绑定
先来举个例子:
上面用到了@PathVariable注解,翻译过来就是路径变量,路径其实就是说url中?之前的路径,其中也可以传递参数,@PathVariable(value = "name",required = false)这样就也变成了非必传参数
注意,下面的参数名必须加上花括号,否则就会被认为是路由映射的一部分,然后再发请求就会报错
如果没加花括号,就如下报错
注意:这里传递的参数是有顺序的!!如果@RequestMapping中的变量是先id后name,那么方法形参名字也必须是先id后name
9.上传文件
使用到@RequestPart注解。以后就会发现,和文件相关的基本上都有part这个字样
如下:
首先要有@P]RequestPart注解,表示要接收文件,用Spring中的一个接口MultipartFile来接收获取到的文件,收到文件之后就要保存到想要保存到的地方,就比如要保存到D:/My_JavaCode/这个目录下,就通过transferTo方法,传递该路径加文件名进行保存。那么如何在postMan中发送请求?如下:
我这是想要发送一张图片,结果如下:
最后就可以在指定的目录中找到该图片了
总结,想要接收文件,就要使用@RequestPart注解(request说明是从请求中取得,Part说明是和文件相关),接收则用MultipartFile接口接收
注意,获取文件名称一定要用getOriginalFileName来获取,而不是getName,因为它获取到的是参数名
10.获取Cookie/Session
我们之前讲过,Cookie是客户端机制,Session是服务器的机制。
http协议自身属于无状态协议,无状态就是指默认情况下http协议的客户端和服务器之间的这次童鞋和下次通信是没有直接关联的。但实际开发中,我们很多时候是需要知道请求之间的关联关系的,这就是cookie和session起到的作用。
简单了解cookie和session的工作流程
1.用户首次登陆,服务器就在Session中新增一个记录,并把Sessionid返回给客户端(一般是通过Set-Cookie字段返回)
2.客户端后续再次与服务器交互时,就会带上sessionid
3.服务器收到请求,就会根据请求中的sessionid在Session中获得对应的用户信息,再进行后续操作
注意
1.Cookie中保留的信息可不仅仅是Sessionid,也不一定是用户信息
2.Sessionid也不一定是通过Cookie或set-Cookie来传递,也可能是URL
获取Cookie
传统获取cookie:
因为SpringMVC是基于ServletAPI构建的原始web框架,也是在Servlet基础上实现的,所以HttpSerletRequest和HttpSerletResponse在SpringMVC中也存在
如上,当我们直接访问时,没有获取到任何cookie,这是因为根本没有设置cookie,所以我们先手动创建几个cookie
然后就会有:
或者如下返回:
其实,设置cookie也可以从后端服务器进行设置,如下:
最后再获取cookie如下:
简洁获取Cookie:
直接加一个@CookieValue注解,表示该参数是从cookie中获取的,这个形参名一般是要与Cookie相同,如果不同,就要在@CookieValue中写入原Cookie的名字(和@RequestParam一样)
获取Session:
Session是服务器端的机制,我们需要先存储再获取
还是通过代码来存储
然后进行Session的获取
传统获取Session:
注意,每次重启服务器一定要重新设置Session,因为Session是存储在服务器内存中的,所以每次服务器停止就代表着内存的释放,所以每次修改代码重启服务器后要重新进行Session的存储。
简洁获取Session:
方式一:使用@SessionAttribute注解(attribute表示属性)
还是和上面一样,如果要用不同的名称接收,就要在@SessionAttribute中加上value="name"
方式二:通过SpringMVC的内置对象HttpSession来获取
11.获取Header
传统获取Header:
简洁获取header:
但是发现没获取到:
这是为什么?因为在Header中UserAgent是以User-Agent形式存在的,但是定义变量时不可以有连字符,所以用UserAgent无法接收,那该怎么办呢?还是用到@RequestHeader中的value属性,如下:
二.响应
1.返回静态页面
首先创建一个前端页面,如下,放在static包下面
然后进行前端页面编写
后端代码
再去访问
欸?为什么没有正确返回,而是把"/index.html"看成了一个普通的字符串。那么SpringMvc如何将index.html识别成一个静态页面呢?
这就需要把@RestController换成@Controller
@RestController和@Controller的关联
MVC中V就是view表示视图,在早期,后端会返回视图给前端,但到了现在,就只会返回前端页面所需要的数据,也就是视图所需要的数据
@RestController=@Controller+@ResponseBody。
Spring本质上是一个容器。Controller告诉Spring要去管理这个类中的代码,所以在类上面加了@Controller,Spring才知道后续访问服务器时,会去扫描这个类
而@ResponseBody这是指定返回数据
所以要想返回视图,就要去掉@ResponseBody
2.返回数据
如果要返回数据,就要加上@ResponseBody
总结:
学到现在,我们就清楚了:如果想要让Spring扫描到这个类,就要在类上面加上@Controller这个注解;如果要想让服务器返回数据,就要再加上@ResponseBody注解;如果仅仅是返回视图,就啥都不用再加了
其实这些注解有些也可以加在方法上。我们来看一下注解的源码:
这个TYPE表示@Controller注解只能加载类上或者接口上
这个TYPE,METHOD表示@RequestMapping注解既可以加在类和接口上,又可以加在方法上
同理,@ResponseBody也可以加在类接口和方法上
3.返回HTML代码片段
后端返回数据时,如果数据中有html代码片段,也会被浏览器解析,如下:
他就是直接将<>解析成了一个标签
同样,比如写了一个form表单:
点击提交就可以跳转到index页面:
4.返回Json
就是要让后端将数据返回之后,前端能够以Json格式接收。那么后端如何返回,前端才能以json格式接收呢?这就要通过抓包来确定了。
前面我们写到后端代码,返回值大多是String,我们随便看一个抓包结果
可知,当以String形式返回响应时,前端接收到的响应的Content-type是text/html格式
其实,当以对象及map返回时,前端接收到的请求是application/json格式。如下:
抓包结果就是application/json
如果返回的是对象,抓包结果也是json。其实这很好想,对象与map都是key-value模型,这号对应json的key-value
5.设置状态码
SpringMVC会根据方法的返回结果自动设置响应状态码,程序员也可以手动指定状态码
6.设置header
一般来说,http响应的报头也会想客户端传递一些附加信息,比如服务程序的名称,请求的资源已经移动到新地址等等,如:Content-Type,location......
这些信息可以通过@RequestMapping注解的属性来实现。学习如何指定响应的header之前,先来看一下@RequestMapping的源码:
1.value:指定请求的url
2.method:指定请求的方法类型
3.consumes:指定请求正文数据类型(content-type)
4.produces:指定返回的内容类型,仅当Request请求头中的(Accept)类型中包含该指定类型,才能返回
5.params:指定request中必须包含某些参数时才能让该方法处理
6.headers:指定request中必须包含某些指定的header值才能让该方法处理
设置content-type:
由上面的分析可知,我们可以通过注解的produces属性来规定请求接收到的数据格式是什么,如下:
当没有加produces属性时,由于返回值是字符串,所以content-type应该是text/html,而设置之后就变成了json
注意,在这里也可以同步设置响应的字符集: