目录
请求
获取URL中参数-@PathVariable
path variable:路径变量
和字面表达的意思一样,这个注解主要作用在 请求URL路径上的数据绑定
默认传递参数写在URL上,Spring MVC就可以获取到
后端实现代码:
java
@RequestMapping("/m8/{id}/{name}")
public String method8(@PathVariable Integer id, @PathVariable("name") String userName){
return "解析参数id:"+id+",name:"+userName;
}
使用浏览器发送请求:http://127.0.0.1:8080/param/m8/5/zhangsan
或者使用Postman发送请求

可以看到,后端正确获取到了URL中的参数
参数对应关系如下:

如果方法参数名称和需要绑定的URL中的变量名称一致时,可以简写,不用给@PathVariable的属性赋值,如上述例子中的id变量
如果方法参数名称和需要绑定的URL中的变量名称不一致时,需要给@PathVariable的属性value赋值,如上述例子中的userName变量
上传文件-@RequestPart
后端代码实现:
java
@RequestMapping("/m9")
public String getfile(@RequestPart("file") MultipartFile file) throws IOException {
//获取⽂件名称
String fileName = file.getOriginalFilename();
//⽂件上传到指定路径
file.transferTo(new File("D:/temp/" + file.getOriginalFilename()));
return "接收到⽂件名称为: "+fileName;
}
使用Postman发送请求:

观察D:/temp路径下,文件是否上传成功

获取Cookie/Session
回顾Cookie
HTTP协议自身是属于"无状态"协议
"无状态"的含义指的是:
默认情况下HTTP协议的客户端和服务器之间的这次通信,和下次通信之间没有直接的联系。但是实际开发中,我们很多时候是需要知道请求之间的关联关系的
例如,登录网站成功后,第二次访问的时候服务器就能知道该请求是否是已经登录过了

就像我们进入京东网页,然后进行登录,当我将该网页叉掉,重新访问时,不需要再次登录
上述图中的"令牌"通常就存储在Cookie字段中
比如去医院挂号
1.看病之前先挂号。挂号时候需要提供身份证号,同时得到了一张"就诊卡",这个就诊卡就相当于患者的"令牌"
2.后续去各个科室进行检查,诊断,开药等操作,都不必再出示身份证了,只要凭就诊卡即可识别出当前患者的身份
3.看完病了之后,不想要就诊卡了,就可以注销这个卡。此时患者的身份和就诊卡的关联就销毁了(类似于网站的注销操作)
4.当患者又来看病,可以办一张新的就诊卡,此时就得到了一个新的"令牌"
理解Session
我们先来了解一下什么是会话
会话:对话的意思

在计算机领域,会话是一个客户与服务器之间的不中断的请求响应。对客户的每个请求,服务器能够识别出请求来自于同一个客户。当一个未知的客户向Web应用程序发送第一个请求时就开始了一个会话。当客户明确结束会话或服务器在一个时限内没有接收到客户的任何请求时,会话就结束了
比如:我们给客服打电话
每次打客服电话,是一个会话。挂断电话,会话就结束了
下次再打客服电话,又是一个新的会话
如果我们长时间不说话,没有新的请求,会话也会结束
服务器同一时刻收到的请求是很多的。服务器需要清楚的区分每个请求是属于哪个用户,也就是属于哪个会话,就需要再在服务器这边记录每个会话以及与用户的信息的对应关系
Session是服务器为了保存用户信息而创建的一个特殊的对象

Session的本质就是一个"哈希表",存储了一些键值对结构。Key就是SessionID,Value就是用户信息(用户信息可以根据需求灵活设计)

SessionId是由服务器生成的一个"唯一性字符串",从Session机制的角度来看,这个唯一性字符串称为"SessionId"。但是站在整个登录流程中看待,也可以把这个唯一性字符串称为"token"。
上述例子中的令牌ID,就可以看做是SessionId,只不过令牌除了ID之外,还会带一些其他信息,比如时间,签名等

1.当用户登陆的时候,服务器在Session中新增一个新记录,并把sessionId返回给客户端(通过HTTP响应中的Set-Cookie字段返回)
2.客户端后续再给服务器发送请求的时候,需要在请求中带上sessionId。(通过HTTP请求中的Cookie字段带上)
3.服务器收到请求之后,根据请求中的sessionId在Session信息中获取到对应的用户信息,再进行后续操作。找不到则重新创建Session,并把SessionID返回

Cookie和Session的区别
·Cookie是客户端保存用户信息的一种机制。Session是服务器端保存用户信息的一种机制
·Cookie和Session之间主要是通过SessionId关联起来的,SessionId是Cookie和Session之间的桥梁
·Cookie和Session经常会在一起配合使用。但是不是必须配合
·完全可以用Cookie来保存一些数据在客户端。这些数据不一定是用户身份信息,也不一定是SessionId
·Session中的sessionId也不需要非得通过Cookie/Set-Cookie传递,比如通过URL传递
获取Cookie
传统获取Cookie
java
@RequestMapping("/m10")
public String method10(HttpServletRequest request,HttpServletResponse response)
{
// 获取所有 cookie 信息
Cookie[] cookies = request.getCookies();
//打印Cookie信息
StringBuilder builder = new StringBuilder();
if (cookies!=null){
for (Cookie ck:cookies) {
builder.append(ck.getName()+":"+ck.getValue());
}
}
return "Cookie信息:"+builder;
}
Spring MVC是基于Servlet API构建的原始Web框架,也是在Servlet的基础上实现的
HttpServletRequest,HttpServletResponse是Servlet提供的两个类,是Spring MVC方法的内置对象。需要时直接在方法中添加声明即可
HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,通过这个对象提供的方法,可以获得客户端请求的所有信息
HttpServletResponse对象代表服务器的响应。HTTP响应的信息都在这个对象中,比如向客户端发送的数据,响应头,状态码等。通过这个对象提供的方法,可以获得服务器响应的所有内容
Spring MVC在这两个对象的基础上进行了封装,给我们提供更加简单的使用方法
此时没有设置Cookie,通过浏览器访问:http://127.0.0.1:8080/param/m10 ,得到Cookie为null

我们设置一下Cookie的值:

再次访问:

从这个例子中,也可以看出Cookie是可以伪造的,也就是不安全的,所以使用Cookie时,后端需要进行Cookie校验
简洁获取Cookie
也有更简洁的方式获取Cookie
java
@RequestMapping("/getCookie")
public String cookie(@CookieValue("Hello") String hello) {
return "Hello:" + hello;
}
运行结果:http://127.0.0.1:8080/param/getCookie

获取Session
Session存储和获取
Session是服务器端的机制,我们需要先存储,才能再获取
Session也是基于HttpServletRequest来存储和获取的
Session存储
java
@RequestMapping("/setSess")
public String setsess(HttpServletRequest request) {
// 获取Session对象
HttpSession session = request.getSession();
if (session != null) {
session.setAttribute("username", "java");
}
return "session 存储成功";
}
这个代码中看不到SeesionId这样的概念的。getSession操作内部提取到请求中Cookie里的SessionId,然后根据SessionId获取到对应的Session对象,Session对象用HttpSession来描述

获取Session有两种方式
java
HttpSession getSession(boolean create);
HttpSession getSession();
HttpSession getSession(boolean create):参数如果为true,则当不存在会话时新建会话;参数如果为false,则当不存在会话时返回null
HttpSession getSession():和getSession(true)含义一样,默认值为true
void setAttribute(String name,Object value):使用指定的名称绑定一个对象到该session会话
Session读取
读取Session可以使用HttpServletRequest
java
@RequestMapping("/getSess")
public String sess(HttpServletRequest request) {
// 如果 session 不存在, 不会⾃动创建
HttpSession session = request.getSession(false);
String username = null;
if (session != null && session.getAttribute("username") != null) {
username = (String) session.getAttribute("username");
}
return "username:" + username;
}
Object getAttribute(String name):返回在该session会话中具有指定名称的对象,如果没有指定名称的对象,则返回null
运行
先存储Session

访问:http://127.0.0.1:8080/param/setSess

通过Fiddler观察http请求和响应情况:
可以看到,Http响应中,通过Set-Cookie告知客户端,把SesionID存储在Cookie中
通过浏览器,可以观察到运行结果:

获取Session

访问http://127.0.0.1:8080/param/getSess

通过Fiddler观察Http请求和响应

可以看到,Http请求时,把SessionId通过Cookie传递到了服务器
简洁获取Session(1)
java
@RequestMapping("/getSess2")
public String sess2(@SessionAttribute(value = "username",required = false) String username) {
return "username:"+username;
}
运行结果:http://127.0.0.1:8080/param/getSess2

简洁获取Session(2)
通过Spring MVC内置对象HttpSession来获取
java
@RequestMapping("/getSess3")
public String sess3(HttpSession session) {
String username = (String)session.getAttribute("username");
return "username:"+username;
}
HttpSession session=request.getSession();
Session不存在的话,会自动进行创建
运行结果:http://127.0.0.1:8080/param/getSess3

获取Header
传统获取header
获取Header也是从HttpServletRequest中获取
java
@RequestMapping("/getHeader")
public String param10(HttpServletRequest request, HttpServletResponse response){
String userAgent = request.getHeader("User-Agent");
return "name" + ":"+userAgent;
}
使用HttpServletRequest提供的getHeader方法来获取,参数对应HTTP请求报头的"Key"
运行结果:http://127.0.0.1:8080/param/getHeader

通过Fiddler观察,获取的User-Agent是否正确

简洁获取Header
java
@RequestMapping("/header")
public String header(@RequestHeader("User-Agent") String userAgent) {
return "userAgent:"+userAgent;
}
@RequestHeader注解的参数值为HTTP请求报头中的"Key"
运行结果:http://127.0.0.1:8080/param/header

响应
在我们前面的代码例子中,都已经设置了响应数据,Http响应结果可以是数据,也可以是静态页面,也可以针对响应设置状态码,Header信息等
返回静态页面
创建前端页面index.html(注意路径)

html代码如下:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index⻚⾯</title>
</head>
<body>
Hello,Spring MVC,我是Index⻚⾯.
</body>
</html>
后端代码:
java
@RestController
public class IndexController {
@RequestMapping("/index")
public Object index(){
//返回index.html
return "/index.html";
}
}
运行结果:http://127.0.0.1:8080/index

从结果却发现,页面未正确返回,http响应把"/index.html"当做了http响应正文的数据
那Spring MVC如何才能识别出来index.html是一个静态页面,并进行返回呢?
我们需要把@RestController改为@Controller
正确代码如下:
java
@Controller
public class IndexController {
@RequestMapping("/index")
public Object index(){
//返回index.html
return "/index.html";
}
}
再次运行:http://127.0.0.1:8080/index

发现页面正确展示了
@RestController 和@Controller有着什么样的关联和区别呢?
咱们前面讲了MVC模式,后端会返回视图,这是早期时的概念

随着互联网的发展,目前项目开发流行"前后端分离"模式,Java主要是用来做后端项目的开发,所以也就不再处理前端相关的内容了
MVC的概念也逐渐发生了变化,View不再返回视图,而是返回显示视图时需要的数据
所以前面使用的@RestController其实是返回需要的数据
@RestController=@Controller+@ResponseBody
@Controller:定义一个控制器,Spring框架启动时加载,把这个对象交给Spring管理
@ResponseBody:定义返回的数据格式为非视图,返回一个text/html信息
@RestController源码:
java
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
@AliasFor(
annotation = Controller.class
)
String value() default "";
}
如果想返回视图的话,只需要把@ResponseBody去掉就可以了,也就是@Controller
返回数据@ResponseBody
我们上面讲到,@ResponseBody表示返回数据
java
//@RestController=@Controller+@ResponseBody
@Controller
@ResponseBody
public class IndexController {
@RequestMapping("/index")
public Object index(){
//返回index.html
return "/index.html";
}
}
加上@ResponseBody注解,该方法就会把"/index.html"当作一个数据返回给前端
运行:http://127.0.0.1:8080/index

@ResponseBody既是类注解,又是方法注解
如果作用在类上,表示该类的所有方法,返回的都是数据,如果作用在方法上,表示该方法返回的是数据也就是说:在类上添加@ResponseBody就相当于在所有的方法上添加了@ResponseBody注解
同样,如果类上有@RestController注解时:表示所有的方法上都添加了@ResponseBody注解,也就是当前类下的所有方法返回值作为响应数据
如果一个类的方法里,既有返回数据的,又有返回页面的,就把@ResponseBody注解添加到对应的方法上即可
java
@Controller
public class IndexController {
@RequestMapping("/index")
public Object index(){
return "/index.html";
}
@RequestMapping("/returnData")
@ResponseBody
public String returnData(){
return "该⽅法返回数据";
}
}
多个注解时,没有先后顺序,先写哪个都可以
运行程序,访问:http://127.0.0.1:8080/returnData
浏览器响应结果如下:

如果去掉@ResponseBody注解,程序会报404错误

程序会默认为需要返回的是视图,根据内容去查找文件,但是查询不到,路径不存在,报404
返回HTML代码片段
后端返回数据时,如果数据中有HTML代码,也会被浏览器解析

运行程序,访问:http://127.0.0.1:8080/returnHtml
浏览器响应结果如下:

通过Fiddler观察响应结果,Content-Type为text/html

响应中的Content-Type常见取值有以下几种:
·text/html:body数据格式是HTML
·text/css:body数据格式是CSS
·application/javascript:body数据格式是JavaScript
·application/json:body数据格式是JSON
如果请求的是js文件,Spring MVC会自动设置Content-Type为application/javascript
如果请求的是css文件,Spring MVC会自动设置Content-Type为text/css
java
@RequestMapping("/index2")
public Object index2(){
return "/a.js";
}
@RequestMapping("/index3")
public Object index3(){
return "/b.css";
}
返回JSON
Spring MVC也可以返回JSON
后端方法返回结果为对象
java
@RequestMapping("/returnJson")
@ResponseBody
public HashMap<String, String> returnJson() {
HashMap<String, String> map = new HashMap<>();
map.put("Java", "Java Value");
map.put("MySQL", "MySQL Value");
map.put("Redis", "Redis Value");
return map;
}
运行程序,访问:http://127.0.0.1:8080/returnJson
浏览器响应结果如下:

通过Fiddler观察响应结果,Content-Type为application/json

设置状态码
Spring MVC会根据我们方法的返回结果自动设置响应状态码,程序员也可以手动指定状态码
通过Spring MVC的内置对象HttpSercletResponse提供的方法来进行设置
java
@RequestMapping(value = "/setStatus")
@ResponseBody
public String setStatus(HttpServletResponse response) {
response.setStatus(401);
return "设置状态码成功";
}
运行程序,访问:http://127.0.0.1:8080/setStatus
浏览器响应结果如下:

状态码不影响页面的展示
通过Fiddler来观察设置的结果

设置Header(了解)
Http响应报头也会向客户端传递一些附加信息,比如服务程序的名称,请求的资源已移动到新地址等,如:Content-Type,Local等
这些信息通过@RequestMapping注解的属性来实现
先来看@RequestMapping的源码
java
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
@Reflective({ControllerMappingReflectiveProcessor.class})
public @interface RequestMapping {
String name() default "";
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
RequestMethod[] method() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}
1.value:指定映射的URL
2.method:指定请求的method类型,如GET、POST等
3.consumes:指定处理请求(request)的提交内容类型(Content-Type),例如application/json,text/html;
4.produces:指定返回的内容类型,还可以同时设置返回值的字符编码
5.params:指定request中必须包含某些参数值时,才让该方法处理
6.headers:指定request中必须包含某些指定的header值,才能让该方法处理请求
了解即可,更多说明参考Mapping Requests :: Spring Framework
设置Content-Type
我们通过设置produces属性的值,设置响应的报头Content-Type
java
@RequestMapping(value = "/returnJson2",produces = "application/json")
@ResponseBody
public String returnJson2() {
return "{\"success\":true}";
}
运行程序,访问:http://127.0.0.1:8080/returnJson2
浏览器响应结果如下:
通过Fiddler来观察设置的结果:

如果不设置prodeces,方法返回结果为String时,Spring MVC默认返回类型是text/html
设置返回类型时,也可以同步设置响应编码
java
@RequestMapping(value = "/returnJson2",produces = "application/json;charset=utf-8")
@ResponseBody
public String returnJson2() {
return "{\"success\":true}";
}
观察Fiddler的响应结果:

设置其他Header
设置其他Header的话,需要使用Spring MVC的内置对象HttpServletResponse提供的方法来进行设置
java
@RequestMapping(value = "/setHeader")
@ResponseBody
public String setHeader(HttpServletResponse response) {
response.setHeader("MyHeader","MyHeaderValue");
return "设置Header成功";
}
运行程序,访问:http://127.0.0.1:8080/setHeader
浏览器响应结果如下:

通过Fiddler来观察设置的结果:
