Spring - 2 ( 14000 字 Spring 入门级教程 )

news2024/9/29 3:29:08

一:Spring Web MVC⼊⻔

Spring Web MVC 是⼀个 Web 框架,简称之为: Spring MVC

要真正的理解什么是 Spring MVC?我们⾸先要搞清楚什么是 MVC?

1.1 MVC 定义

MVC 是 Model View Controller 的缩写,它是软件⼯程中的⼀种软件架构设计模式,它把软件系统分为模型、视图和控制器三个基本部分

在这里插入图片描述

  • View(视图) 指在应⽤程序中专⻔⽤来与浏览器进⾏交互,展⽰数据的资源.
  • Model(模型) 是应⽤程序的主体部分,⽤来处理程序中数据逻辑的部分.
  • Controller(控制器)可以理解为⼀个分发器,⽤来决定对于视图发来的请求,需要⽤哪⼀个模型来处理,以及处理完后需要跳回到哪⼀个视图。即⽤来连接视图和模型

1.2 什么是Spring MVC

MVC 是⼀种架构设计模式, 也⼀种思想, ⽽ Spring MVC 是对 MVC 思想的具体实现. 除此之外, SpringMVC还是⼀个Web框架.

总结来说,Spring MVC 是⼀个实现了 MVC 模式的 Web 框架.所以, Spring MVC主要关注有两个点:

  1. MVC
  2. Web框架

其实, Spring MVC 我们在前⾯已经⽤过了, 在创建 Spring Boot 项⽬时,我们勾选的 Spring Web 框架其实就是 Spring MVC 框架:

在这里插入图片描述

Spring Boot 只是实现Spring MVC的其中⼀种方式,Spring Boot 可以添加很多依赖, 借助这些依赖实现不同的功能. Spring Boot 通过添加Spring WebMVC框架, 来实现web功能.

Spring在实现MVC时, 也结合⾃⾝项⽬的特点, 做了⼀些改变, 相对⽽⾔, 下⾯这个图或许更加合适⼀些.

在这里插入图片描述

1.3 学习Spring MVC

学习Spring MVC, 重点也就是学习如何通过浏览器和⽤⼾程序进⾏交互.

主要分以下三个⽅⾯:

  1. 建⽴连接:将⽤⼾(浏览器)和 Java 程序连接起来,也就是访问⼀个地址能够调⽤到我们的Spring 程序。
  2. 请求: ⽤⼾请求的时候会带⼀些参数,在程序中要想办法获取到参数, 所以请求这块主要是 获取参数的功能.
  3. 响应: 执⾏了业务逻辑之后,要把程序执⾏的结果返回给⽤⼾, 也就是响应.

1.3.1 项目准备

Spring MVC 项⽬创建和 Spring Boot 创建项⽬相同,在创建的时候选择 Spring Web 就相当于创建了Spring MVC 的项⽬.

创建项⽬时, 勾选上 Spring Web 模块即可,如下图所⽰:
在这里插入图片描述

1.4 建立连接 - 1

在 Spring MVC 中使⽤ @RequestMapping 来实现 URL 路由映射 ,也就是浏览器连接程序的作⽤

我们先来看看代码怎么写:

创建⼀个 UserController 类,实现⽤⼾通过浏览器和程序的交互,具体实现代码如下:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@RestController
public class UserController {
    // 路由器规则注册
    @RequestMapping("/sayHi")
    public String sayHi(){
        return "hello,Spring MVC";
    }
}

⽅法名和路径名称⽆需⼀致:

接下来访问: http://127.0.0.1:8080/sayHi, 就可以看到程序返回的数据了

在这里插入图片描述

1.5 @RequestMapping 注解

@RequestMapping 是 Spring Web MVC 应⽤程序中最常被⽤到的注解之⼀,它是⽤来注册接⼝的路由映射的,表⽰服务收到请求时, 路径为 /sayHi 的请求就会调⽤ sayHi 这个⽅法的代码.

路由映射: 当⽤⼾访问⼀个 URL 时, 将⽤⼾的请求对应到程序中某个类的某个⽅法的过程就叫路由映射.

1.5.1 @RestController

既然 @RequestMapping 已经可以达到我们的⽬的了, 我们为什么还要加 @RestController呢?

我们把 @RestController 去掉, 再来访问⼀次:
在这里插入图片描述
可以看到, 程序报了404, 找不到该⻚⾯,这就是 @RestController 起到的作⽤.

一个项⽬中, 会有很多类, 每个类可能有很多的⽅法, Spring程序怎么知道要执⾏哪个⽅法呢?

Spring会对所有的类进⾏扫描, 如果类加了注解@RestController, Spring才会去看这个类⾥⾯的⽅法有没有加 @RequestMapping 这个注解, 当然他的作⽤不⽌这⼀点, 咱们先⽤, 后⾯再详细讲

1.5.2 @RequestMapping 使⽤

@RequestMapping 即可修饰类,也可以修饰⽅法 ,当修饰类和⽅法时,访问的地址是类路径 + ⽅法路径.

@RequestMapping标识⼀个类:设置映射请求的请求路径的初始信息

@RequestMapping标识⼀个⽅法:设置映射请求请求路径的具体信息

@RequestMapping("/user")
@RestController
public class UserController {
    @RequestMapping("/sayHi")
    public String sayHi(){
        return "hello,Spring MVC";
    }
}

访问地址:http://127.0.0.1:8080/user/sayHi

在这里插入图片描述
注意:@RequestMapping 的URL 路径最前⾯加不加 / (斜杠)都可以, Spring程序启动时, 会进⾏判断, 如果前⾯没有加 / , Spring会拼接上⼀个 /(通常情况下, 我们加上 /)

@RequestMapping("user")
@RestController
public class UserController {
    @RequestMapping("sayHi")
    public String sayHi(){
        return "hello,Spring MVC";
    }
}

访问http://127.0.0.1:8080/user/sayHi, 依然可以正确响应.

@RequestMapping 的URL路径也可以是多层路径, 最终访问时, 依然是 类路径 + ⽅法路径

@RequestMapping("/user/m1")
@RestController
public class UserController {
    @RequestMapping("/say/hi")
    public String sayHi(){
        return "hello,Spring MVC";
    }
}

访问路径: http://127.0.0.1:8080/user/m1/say/hi

在这里插入图片描述

1.5.3@RequestMapping 是 GET 还是 POST 请求?

@RequestMapping 既⽀持Get请求, ⼜⽀持Post请求. 同理, 也⽀持其他的请求⽅式.

那如何指定GET或者POST类型呢?

1.5.3.1 指定GET/POST⽅法类型

我们可以显⽰的指定@RequestMapping 来接收POST的情况,如下所⽰:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@RestController
public class UserController {
    @RequestMapping(value = "/getRequest",method= RequestMethod.POST)
    public String sayHi(){
        return "get request...";
    }
}

1.6 Postman介绍

从上⾯的案例中, 也发现了⼀个新的问题, 就是我们测试后端⽅法时, 还需要去写前端代码. 这对我们来说, 是⼀件⿇烦⼜痛苦的事情.

随着互联⽹的发展, 也随着项⽬难度的增加, 企业也按照开发的功能, 把⼈员拆分成了不同的团队. 界⾯显⽰交给"前端开发⼯程师", 业务逻辑的实现交给 “后端开发⼯程师”.

后端开发⼯程师, 不要求也不需要掌握前端技能了.

那后端开发⼯程师, 如何测试⾃⼰的程序呢? – 使⽤专业的接⼝测试⼯具

1.6.1 创建请求

在这里插入图片描述
在这里插入图片描述
界⾯介绍:

在这里插入图片描述

1.6.2 传参

  1. 普通传参, 也就是通过查询字符串来传参

查询字符串就是请求的参数

在这里插入图片描述

  1. form-data(完整表⽰为: multipart/form-data)

表单提交的数据, 在 form 标签中加上 enctyped=“multipart/form-data” , 通常⽤于提交图⽚/⽂件. 对应 Content-Type: multipart/form-data

在这里插入图片描述
3. x-www-form-urlencoded

form表单, 对应 Content-Type: application/x-www-from-urlencoded

在这里插入图片描述
4. raw

可以上传任意格式的⽂本,可以上传text、json、xml、html等

在这里插入图片描述

1.7 请求 - 2

访问不同的路径, 就是发送不同的请求. 在发送请求时, 可能会带⼀些参数, 所以学习Spring的请求, 主要是学习如何传递参数到后端以及后端如何接收.

1.7.1 传递单个参数

接收单个参数, 在 Spring MVC 中直接⽤⽅法中的参数就可以,⽐如以下代码:

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/param")
public class ParamController {
    @RequestMapping("/m1")
    public String method1(String name){
        return "接收到参数name:"+ name;
    }
}

咱们使⽤浏览器发送请求并传参:http://127.0.0.1:8080/param/m1?name=spring

在这里插入图片描述
可以看到, 后端程序正确拿到了name参数的值.

Spring MVC 会根据⽅法的参数名, 找到对应的参数, 赋值给⽅法
在这里插入图片描述
如果参数不⼀致, 是获取不到参数的.

⽐如请求URL: http://127.0.0.1:8080/param/m1?name1=spring
响应结果:
在这里插入图片描述
注意事项:
使⽤基本类型来接收参数时, 参数必须传(除boolean类型), 否则会报500错误

类型不匹配时, 会报400错误.

@RequestMapping("/m1/int")
public Object method1GetInt(int age){
        return "接收到参数age:" + age;
        }
  1. 正常传递参数

http://127.0.0.1:8080/param/m1/int?age=1

在这里插入图片描述
通过Fiddler观察请求和响应, HTTP响应状态码为200, Content-Type 为 text/html
在这里插入图片描述
2. 不传递age参数

http://127.0.0.1:8080/param/m1/int

在这里插入图片描述
通过Fiddler观察请求和响应, HTTP响应状态码为500
在这里插入图片描述
尝试观察程序的错误⽇志, 并解决
在这里插入图片描述
3. 传递参数类型不匹配

http://127.0.0.1:8080/param/m1/int?age=abc

在这里插入图片描述
通过Fiddler观察请求和响应, HTTP响应状态码为400

在这里插入图片描述
对于包装类型, 如果不传对应参数,Spring 接收到的数据则为null,所以企业开发中,对于参数可能为空的数据,建议使⽤包装类型

1.7.2 传递多个参数

如何接收多个参数呢?

和接收单个参数⼀样, 直接使⽤⽅法的参数接收即可. 使⽤多个形参.

@RequestMapping("/m2")
public Object method2(String name, String password) {
        return "接收到参数name:" + name + ", password:" + password;
        }

使⽤浏览器发送请求并传参: http://127.0.0.1:8080/param/m2?name=zhangsan&password=123456

在这里插入图片描述
可以看到, 后端程序正确拿到了name和password参数的值
在这里插入图片描述
当有多个参数时,前后端进⾏参数匹配时,是以参数的名称进⾏匹配的,因此参数的位置是不影响后端获取参数的结果.

⽐如访问: http://127.0.0.1:8080/param/m2?password=123456&name=zhangsan 同样可以拿到正确的结果

在这里插入图片描述

1.7.3 传递对象

如果参数⽐较多时, ⽅法声明就需要有很多形参. 并且后续每次新增⼀个参数, 也需要修改⽅法声明,我们不妨把这些参数封装为⼀个对象.

Spring MVC 也可以⾃动实现对象参数的赋值,⽐如 Person 对象:

**public class Person {
    private int id;
    private String name;
    private String password;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}**

传递对象代码实现:

@RequestMapping("/m3")
public Object method3(Person p){
        return p.toString();
        }

使⽤浏览器发送请求并传参: http://127.0.0.1:8080/param/m3?
id=5&name=zhangsan&password=123456
在这里插入图片描述
可以看到, 后端程序正确拿到了Person对象⾥各个属性的值
在这里插入图片描述
Spring 会根据参数名称⾃动绑定到对象的各个属性上, 如果某个属性未传递, 则赋值为null(基本类型则
赋值为默认初识值, ⽐如int类型的属性, 会被赋值为0)

1.7.4 后端参数重命名

某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不⼀致,⽐如前端传递了⼀个time 给后端,⽽后端是使⽤ createtime 字段来接收的,这样就会出现参数接收不到的情况,如果出现这种情况,我们就可以使⽤ @RequestParam 来重命名前后端的参数值.

@RequestMapping("/m4")
public Object method_4(@RequestParam("time") String createtime) {
        return "接收到参数createtime:" + createtime;
        }

使⽤浏览器发送请求并传参: http://127.0.0.1:8080/param/m4?time=2023-09-12

在这里插入图片描述
可以看到, Spring可以正确的把浏览器传递的参数time绑定到了后端参数caretetime参数上

此时, 如果浏览器使⽤createtime进⾏参数传递呢?访问URL: http://127.0.0.1:8080/param/m4?createtime=2023-09-12

在这里插入图片描述
错误⽇志信息为:
在这里插入图片描述
控制台打印⽇志显⽰: 请求参数 ?time? 不存在

可以得出结论:

  1. 使⽤ @RequestParam 进⾏参数重命名时, 请求参数只能和 @RequestParam 声明的名称⼀致, 才能进⾏参数绑定和赋值.
  2. 使⽤ @RequestParam 进⾏参数重命名时, 参数就变成了必传参数.

⾮必传参数设置

如果我们的实际业务前端的参数是⼀个⾮必传的参数, 针对上述问题, 如何解决呢?

先来了解下参数必传的原因, 我们查看 @RequestParam 注解的实现细节就可以发现端倪,注解
实现如下:

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
    @AliasFor("name")
    String value() default "";
    @AliasFor("value")
    String name() default "";
    boolean required() default true;
    String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n"
}

可以看到 required 的默认值为true, 表⽰含义就是: 该注解修饰的参数默认为必传

既然如此, 我们可以通过设置 @RequestParam 中的required=false 来避免不传递时报错,

具体实现如下:

@RequestMapping("/m4")
public Object method4(@RequestParam(value = "time", required = false) String cre
        return "接收到参数createtime:" + createtime;
        }

1.7.5 传递数组

Spring MVC 可以⾃动绑定数组参数的赋值

@RequestMapping("/m5")
public String method5(String[] arrayParam) {
        return Arrays.toString(arrayParam);
        }

使⽤浏览器发送请求并传参:

数组参数:请求参数名与形参数组名称相同且请求参数为多个, 后端定义数组类型形参即可接收参数http://127.0.0.1:8080/param/m5?arrayParam=zhangsan&arrayParam=lisi&arrayParam=wangwu
或者使⽤ http://127.0.0.1:8080/param/m6?listParam=zhangsan%2clisi%2cwangwu
或者使⽤ http://127.0.0.1:8080/param/m5?arrayParam=zhangsan,lisi,wangwu

浏览器响应结果:

在这里插入图片描述

1.7.6 传递集合

集合参数:和数组类似, 同⼀个请求参数名有为多个, 且需要使⽤ @RequestParam 绑定参数关系

请求⽅式和数组类似:
浏览器传参:‘

  • ⽅式⼀:http://127.0.0.1:8080/param/m6listParam=zhangsan&listParam=lisi&listParam=wang
  • wu ⽅式⼆:
    http://127.0.0.1:8080/param/m6?listParam=zhangsan%2clisi%2cwangwu
**@RequestMapping("/m6")
public String method6(@RequestParam List<String> listParam){
        return "size:"+listParam.size() + ",listParam:"+listParam;
        }**

Postman传参测试:
在这里插入图片描述

1.7.7 传递JSON数据

JSON就是⼀种数据格式, 有⾃⼰的格式和语法, 使⽤⽂本表⽰⼀个对象或数组的信息, 因此JSON本质是字符串. 主要负责在不同的语⾔中数据传递和交换.

JSON 是⼀个字符串,其格式⾮常类似于 JavaScript 对象字⾯量的格式,我们先来看⼀段JSON数据:

{
  "squadName": "Super hero squad",
  "homeTown": "Metro City",
  "formed": 2016,
  "secretBase": "Super tower",
  "active": true,
  "members": [
    {
      "name": "Molecule Man",
      "age": 29,
      "secretIdentity": "Dan Jukes",
      "powers": ["Radiation resistance", "Turning tiny", "Radiation blast"]
    },
    {
      "name": "Madame Uppercut",
      "age": 39,
      "secretIdentity": "Jane Wilson",
      "powers": ["Million tonne punch", "Damage resistance", "Superhuman strength"]
    },
    {
      "name": "Eternal Flame",
      "age": 1000000,
      "secretIdentity": "Unknown",
      "powers": ["Immortality", "Heat Immunity", "Inferno", "Teleportation"]
    }
  ]
}

也可以压缩表⽰:

{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBaseSuper tower","active":true,"members":[{"name":"M Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madameppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million ton punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}

JSON的语法:

  1. 数据在 键值对(Key/Value) 中
  2. 数据由逗号 , 分隔
  3. 对象⽤ {} 表⽰
  4. 数组⽤ [] 表⽰
  5. 值可以为对象, 也可以为数组, 数组中可以包含多个对象

JSON的两种结构

  1. 对象: ⼤括号 {} 保存的对象是⼀个⽆序的 键值对 集合. ⼀个对象以左括号 { 开始, 右括号 }结束。每个"键"后跟⼀个冒号 : ,键值对使⽤逗号 , 分隔
  2. 数组: 中括号 [] 保存的数组是值(value)的有序集合. ⼀个数组以左中括号 [ 开始, 右中括号 ] 结束,值之间使⽤逗号 , 分隔。

在这里插入图片描述
所以, 以下都是合法的JSON数据:

{"name":"admin","age":18}
["hello", 3.1415, "json"]
[{"name":"admin","age":18},{"name":"root","age":16},{"name":"张三","age":20}]

JSON优点:

  1. 简单易⽤: 语法简单,易于理解和编写,可以快速地进⾏数据交换
  2. 跨平台⽀持: JSON可以被多种编程语⾔解析和⽣成, 可以在不同的平台和语⾔之间进⾏数据交换和传输
  3. 轻量级: 相较于XML格式, JSON数据格式更加轻量级, 传输数据时占⽤带宽较⼩, 可以提⾼数据传输速度
  4. 易于扩展: JSON的数据结构灵活,⽀持嵌套对象和数组等复杂的数据结构,便于扩展和使⽤
  5. 安全性: JSON数据格式是⼀种纯⽂本格式,不包含可执⾏代码, 不会执⾏恶意代码,因此具有较⾼的安全性

基于以上特点, JSON在Web应⽤程序中被⼴泛使⽤, 如前后端数据交互、API接⼝数据传输等.

接收JSON对象, 需要使⽤ @RequestBody 注解

RequestBody: 请求正⽂,意思是这个注解作⽤在请求正⽂的数据绑定,请求参数必须在写在请求正⽂中

@RequestMapping(value = "/m7")
public Object method7(@RequestBody Person person) {
        return person.toString();
        }

使⽤Postman来发送json请求参数:

在这里插入图片描述
可以看到, 后端正确接收了,通过Fiddler观察⼀下请求参数:

在这里插入图片描述

1.7.8 获取URL中参数@PathVariable

path variable: 路径变量

和字⾯表达的意思⼀样, 这个注解主要作⽤在请求URL路径上的数据绑定,默认传递参数写在URL上,SpringMVC就可以获取到

@RequestMapping("/m8/{id}/{name}")
public String method8(@PathVariable Integer id, @PathVariable("name") String use
        return "解析参数id:"+id+",name:"+userName;
        }

使⽤浏览器发送请求:http://127.0.0.1:8080/param/m8/5/zhangsan

或者使⽤Postman发送请求
在这里插入图片描述

可以看到, 后端正确获取到了URL中的参数
参数对应关系如下:
在这里插入图片描述
如果⽅法参数名称和需要绑定的URL中的变量名称⼀致时, 可以简写, 不⽤给@PathVariable的属性赋值, 如上述例⼦中的id变量

如果⽅法参数名称和需要绑定的URL中的变量名称不⼀致时, 需要@PathVariable的属性value赋值,如上述例⼦中的userName变量.

1.7.9 上传⽂件@RequestPart

@RequestMapping("/m9")
public String getfile(@RequestPart("file") MultipartFile file) throws IOExceptio
//获取⽂件名称
        String fileName = file.getOriginalFilename();
//⽂件上传到指定路径
        file.transferTo(new File("D:/temp/" + file.getOriginalFilename()));
        return "接收到⽂件名称为: "+fileName;
        }

使⽤Postman发送请求:
在这里插入图片描述
观察 D:/temp 路径下, ⽂件是否上传成功:
在这里插入图片描述

1.8 获取Cookie

HTTP 协议⾃⾝是属于 “⽆状态” 协议,即默认情况下 HTTP 协议的客⼾端和服务器之间的这次通信, 和下次通信之间没有直接的联系.

但是实际开发中, 我们很多时候是需要知道请求之间的关联关系的.

在这里插入图片描述
上述图中的 “令牌” 通常就存储在 Cookie 字段中.

此时在服务器这边就需要记录"令牌"信息, 以及令牌对应的⽤⼾信息, 这个就是 Session 机制所做的⼯作.

1.8.1 理解Session

会话: 对话的意思
在这里插入图片描述
在计算机领域, 会话是⼀个客⼾与服务器之间的不中断的请求响应. 对客⼾的每个请求,服务器能够识别出请求来⾃于同⼀个客⼾. 当⼀个未知的客⼾向Web应⽤程序发送第⼀个请求时就开始了⼀个会话.当客⼾明确结束会话或服务器在⼀个时限内没有接受到客⼾的任何请求时,会话就结束了.

⽐如我们打客服电话,每次打客服电话, 是⼀个会话. 挂断电话, 会话就结束了,下次再打客服电话, ⼜是⼀个新的会话,如果我们⻓时间不说话, 没有新的请求, 会话也会结束.

服务器同⼀时刻收到的请求是很多的. 服务器需要清楚的区分每个请求是从属于哪个⽤⼾, 也就是属于哪个会话, 就需要在服务器这边记录每个会话以及与⽤⼾的信息的对应关系.

Session是服务器为了保存⽤⼾信息⽽创建的⼀个特殊的对象.

在这里插入图片描述
Session的本质就是⼀个 “哈希表”, 存储了⼀些键值对结构. Key 就是SessionID, Value 就是⽤⼾信息(⽤⼾信息可以根据需求灵活设计).

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

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

在这里插入图片描述
Session 默认是保存在内存中的. 如果重启服务器则 Session 数据就会丢失.

1.8.2 Cookie 和 Session 的区别

  • Cookie 是客⼾端保存⽤⼾信息的⼀种机制. Session 是服务器端保存⽤⼾信息的⼀种机制.
  • Cookie 和 Session之间主要是通过 SessionId 关联起来的, SessionId 是 Cookie 和 Session之间的桥梁
  • Cookie 和 Session 经常会在⼀起配合使⽤. 但是不是必须配合.
  • 完全可以⽤ Cookie 来保存⼀些数据在客⼾端. 这些数据不⼀定是⽤⼾⾝份信息, 也不⼀定是SessionId
  • Session 中的sessionId 也不需要⾮得通过 Cookie/Set-Cookie 传递, ⽐如通过URL传递.

1.8.3 获取Cookie

传统获取Cookie:

@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;
}

此时没有设置Cookie, 通过浏览器访问: http://127.0.0.1:8080/param/m10 ,得到Cookie为null

在这里插入图片描述
我们设置⼀下Cookie的值
在这里插入图片描述
再次访问:
在这里插入图片描述
从这个例⼦中, 也可以看出Cookie是可以伪造的, 也就是不安全的, 所以使⽤Cookie时, 后端需要进⾏Cookie校验

简洁获取Cookie

@RequestMapping("/getCookie")
public String cookie(@CookieValue("bite") String bite) {
        return "bite:" + bite;
}

运⾏结果: http://127.0.0.1:8080/param/getCookie
在这里插入图片描述

1.9 获取Session

Session是服务器端的机制, 我们需要先存储, 才能再获取
Session 也是基于HttpServletRequest 来存储和获取的

Session存储

@RequestMapping("/setSess")
public String setsess(HttpServletRequest request) {
        // 获取Session对象
        HttpSession session = request.getSession();
            if (session != null) {
             session.setAttribute("username", "java");
            }
        return "session 存储成功";
}

这个代码中看不到 SessionId 这样的概念的. getSession 操作内部提取到请求中的Cookie ⾥的SessionId, 然后根据SessionId获取到对应的Session 对象, Session 对象⽤HttpSession来描述

在这里插入图片描述
获取Session有两种⽅式:

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 会话

1.9.1 Session读取

读取 Session 可以使⽤ HttpServletRequest

@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;
}

运⾏:
先设置Session: http://127.0.0.1:8080/param/setSess
在这里插入图片描述
通过Fiddler观察Http请求和响应情况:
在这里插入图片描述
可以看到, Http响应中, 通过Set-Cookie告知客⼾端, 把SessionID存储在Cookie中

通过浏览器, 可以观察到运⾏结果:

在这里插入图片描述
获取Session: http://127.0.0.1:8080/param/getSess
在这里插入图片描述
通过Fiddler观察Http请求和响应
在这里插入图片描述
可以看到, Http请求时, 把SessionId通过Cookie传递到了服务器.

简洁获取 Session(1)

@RequestMapping("/getSess2")
public String sess2(@SessionAttribute(value = "username",required = false) String
        return "username:"+username;
}

运⾏结果: http://127.0.0.1:8080/param/getSess2
在这里插入图片描述
简洁获取 Session(2)
通过Spring MVC内置对象HttpSession 来获取

@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

在这里插入图片描述

1.10 获取Header

传统获取 header:获取Header也是从 HttpServletRequest 中获取

@RequestMapping("/param10")
public String param10(HttpServletRequest request, HttpServletResponse response)
        String userAgent = request.getHeader("User-Agent");
        return name + ":"+userAgent;
}

运⾏结果: http://127.0.0.1:8080/param/getHeader

在这里插入图片描述
通过Fiddler观察, 获取的User-Agent是否正确

在这里插入图片描述
简洁获取 Header:

@RequestMapping("/header")
public String header(@RequestHeader("User-Agent") String userAgent) {
        return "userAgent:"+userAgent;
}

运⾏结果: http://127.0.0.1:8080/param/getHeader2

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1614794.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

丰田是如何用精益理念改变制造业的?

丰田&#xff0c;这个全球知名的汽车制造商&#xff0c;不仅以其高质量的产品赢得了消费者的信赖&#xff0c;更以其独特的精益理念深刻改变了整个制造业的面貌。那么&#xff0c;丰田究竟是如何用精益理念引领制造业变革的呢&#xff1f;天行健精益管理培训公司解析如下&#…

了解BACnet的对象模型 (三)

文章目录 前言18个对象BACnet 对象的属性设备对象&#xff08;Device&#xff09;的属性输入输出值对象类型及其属性 在代码中的表达Device对象的属性模拟输入对象的属性 小结 前言 在楼宇自控网络中&#xff0c;各种设备之间要进行数据交换&#xff0c;为了能够实现设备的互操…

[C++][算法基础]求组合数(II)

给定 &#x1d45b; 组询问&#xff0c;每组询问给定两个整数 &#x1d44e;&#xff0c;&#x1d44f;&#xff0c;请你输出 的值。 输入格式 第一行包含整数 &#x1d45b;。 接下来 &#x1d45b; 行&#xff0c;每行包含一组 &#x1d44e; 和 &#x1d44f;。 输出格…

【Java框架】SpringMVC(二)——SpringMVC数据交互

目录 前后端数据交互RequestMapping注解基于RequestMapping注解设置接口的请求方式RequestMapping注解的常用属性一个方法配置多个接口method属性params属性headers属性consumes属性produces属性 SpringMVC中的参数传递默认单个简单参数默认多个简单参数默认参数中有基本数据类…

机器学习-11-基于多模态特征融合的图像文本检索

总结 本系列是机器学习课程的系列课程&#xff0c;主要介绍机器学习中图像文本检索技术。此技术把自然语言处理和图像处理进行了融合。 参考 2024年&#xff08;第12届&#xff09;“泰迪杯”数据挖掘挑战赛 图像特征提取&#xff08;VGG和Resnet特征提取卷积过程详解&…

Python 比较文本文件

1、问题背景 我们需要比较一个文本文件 F 与路径下多个其他文本文件之间的差异。我们已经编写了以下代码&#xff0c;但只能输出一个文件的比较结果。我们需要修改代码&#xff0c;以便比较所有文件并打印所有结果。 import difflib import fnmatch import osfilelist[] f op…

Linux 网络操作命令Telnet

Telnet 尽管 Telnet 已经逐渐被更安全的 SSH 协议所取代&#xff0c;但在某些特定场景下&#xff0c;如对旧系统的维护或教育目的&#xff0c;Telnet 仍然有其使用价值。本文将介绍如何在 Linux 系统中安装 Telnet 客户端&#xff0c;以及如何使用它进行远程登录。 用户使用 t…

基于SpringBoot+Vue的网上摄影工作室(含源码数据库+文档免费送)

项目演示视频&#xff1a; 基于SpringBootVue的网上摄影工作室&#xff08;含源码数据库文档免费送&#xff09; 基于SpringBootVue的网上摄影工作室&#xff08;含源码数据库文档免费送&#xff09; 开发系统:Windows10 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工…

JEECG表格选中状态怎么去掉

官网代码&#xff08;在取消选中状态的时候不生效&#xff09; rowSelection() {return {onChange: (selectedRowKeys, selectedRows) > {console.log(selectedRowKeys: ${selectedRowKeys}, selectedRows: , selectedRows);},getCheckboxProps: record > ({props: {disa…

亚马逊、Lazada、速卖通怎么提高复购率?如何利用自养号测评实现销量飙升

对于跨境卖家来说&#xff0c;抓住客户是最重要的&#xff0c;很多卖家都把大部分心思放在如何吸引新客户上&#xff0c;忽视了已有客户的维护。其实相较于投广告、报秒杀活动吸引新客户&#xff0c;维护好已有客户&#xff0c;提升复购率的成本更低。当然&#xff0c;维护好客…

微软如何打造数字零售力航母系列科普02 --- 微软低代码应用平台加速企业创新 - 解放企业数字零售力

微软低代码应用平台推动企业创新- 解放企业数字零售力 微软在2023年GARTNER发布的魔力象限图中处于头部领先&#xff08;leader&#xff09;地位。 其LCAP产品是Microsoft Power Apps&#xff0c;扩展了AI Builder、Dataverse、Power Automate和Power Pages&#xff0c;这些都包…

Java 基础知识易错记录

Java 基础知识易错记录 ①运算符 ②continue和break ③成员变量 局部变量 ④switch case ⑤StringBuffer StringBuilder ⑥重载 重写 ⑦throw throws 运算符 public static void main(String[] args) {int a 1;System.out.println(a);System.out.println(a);}在后&#xff…

Node.js -- path模块

path.resolve(常用) // 导入fs const fs require(fs); // 写入文件 fs.writeFileSync(_dirname /index.html,love); console.log(_dirname /index.html);// D:\nodeJS\13-path\代码/index.html 我们之前使用的__dirname 路径 输出的结果前面是正斜杠/ &#xff0c;后面部分是…

测试的分类(2)

目录 按照执行方式分类 静态测试 动态测试 按照测试方法 灰盒测试 按照测试阶段分类 单元测试 集成测试 系统测试 冒烟测试 回归测试 按照执行方式分类 静态测试 所谓静态测试就是不实际运行被测软件,只是静态地检查程序代码, 界面或文档中可能存在错误的过程. 不以…

Git | 分支管理

Git | 分支管理 文章目录 Git | 分支管理1、理解分支2、创建分支&&切换分支3、合并分支4、删除分支5、合并冲突6、分支管理策略合并分支模式实际工作中分支策略bug分支删除临时分支 1、理解分支 分支就类似分身。 在版本回退中&#xff0c;每次提交Git都会将修改以git…

.net core webapi 高颜值的接口管理系统界面取代swagger,更好调试和查看

.net core webapi 高颜值的接口管理系统界面取代swagger&#xff0c;更好调试和查看 安装 dotnet add package IGeekFan.AspNetCore.Knife4jUI --version 0.0.16配置文档&#xff1a; 配置起始页 builder.Services.AddSwaggerGen(c > {// 配置 Swagger 文档相关信息c.Swa…

圣若热城堡、贝伦塔、热罗尼莫斯修道院 BIBM 2024在里斯本等你

会议之眼 快讯 2024年BIBM&#xff08;IEEE International Conference on Bioinformatics and Biomedicine&#xff09;即IEEE生物信息学与生物医学国际会议将于 2024年 12月3日-6日在葡萄牙里斯本举行&#xff01;这个会议由IEEE&#xff08;电气和电子工程师协会&#xff09…

CCF PTA 2023年11月C++卫星发射

【问题描述】 在 2050 年卫星发射技术已经得到极大发展&#xff0c;我国将援助 A 国建立远轨道卫星导航系统&#xff0c;该项目计划第 一个天发射一颗卫星&#xff1b;之后两天&#xff08;第二天和第三天&#xff09;&#xff0c;每天发射两颗卫星&#xff1b;之后三天&#…

牛客 NC205 跳跃游戏(三)【中等 贪心 Java,Go,PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/14abdfaf0ec4419cbc722decc709938b 思路 参考答案Java import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定的值即可*** …

面向对象设计模式之概念

设计模式系列的观点结合了《HeadFirst设计模式》(中文版)以及《设计模式&#xff1a;可复用面向对象软件的基础》两本书的知识&#xff0c;以及Sunny(刘伟)的博客 《HeadFirst设计模式》(中文版)&#xff1a; 百度网盘链接&#xff1a;https://pan.baidu.com/s/1osvnUGZZREm8Jb…