Spring Web MVC入门(2)——请求(下)

简介: Spring Web MVC入门(2)——请求

Spring Web MVC入门(2)——请求(上):https://developer.aliyun.com/article/1528170


八、获取URL中参数@PathVariable


       path variable路径变量

       和字面表达的意思一样,这个注解主要作用在请求URL路径上的数据绑定(默认传递参数写在URL上,Spring MVC就可以获取到)

       后端代码:

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

       使用浏览器,访问:http://127.0.0.1:8080/d1/m2/5/zhangsan  ,页面如下:

       

       使用Postman页面如下:

       

       可以看到,后端接收到了URL的参数,下图是参数对应关系:

如果方法参数名称和需要绑定的URL的变量名称一致时,可以简写,不用给@PathVariable的属性赋值,例如上述例子中的id变量。

如果方法参数名称和需要绑定的URL的变量名称不一致时,需要给@PathVariable的属性赋值,如上述例子中的userName变量。


九、上传文件@RequestPart


       使用注解RequestPart

       后端代码实现:

    @RequestMapping("m3")
    public String getFile(@RequestPart("file") MultipartFile file) throws IOException {
        //获取文件名称
        String fileName = file.getOriginalFilename();
        //文件上传到指定路径
        file.transferTo(new File("D:/desktop/file/javaEE/temp" + file.getOriginalFilename()));
        return "接收到的文件名称为: " + fileName;
    }

       Postman页面如下:

       查看电脑 D:/desktop/file/javaEE/temp/ 路径下是否有cat.jpg文件:


十、获取Cookie / Session


       HTTP协议自身是属于 “无状态” 协议“无状态” :默认情况下,HTTP协议的客户端和服务器的这次通信,和下次通信之间没有直接的联系(也可以理解成 “无记忆”)

       在计算机领域,我们认为 “无状态” 是好的,相反,“有状态” 就不好

       但是实际开发中,很多时候是需要知道请求之间有关联的关系,例如我登录第三方网站,第一次登录成功后,后续的访问就不用继续输入账户密码,可以直接登录成功,所以这时候服务器就需要知道我之前是登录过了的。

1、回顾Cookie

       下面简单介绍一下Cookie,详细介绍可以看我之前写的博客:网络原理 - HTTP / HTTPS(2)

      Cookie本质是浏览器这边,本地化永久存储数据的机制,是一个身份标识,相当于令牌

       客户端和服务器之间的登录请求交互,大概流程图如下:

       

       Cookie就像就诊卡去医院看病,第一次去陌生的医院看病,进行挂号,一般都是要买个就诊卡的,医生给你看病时,第一句也不是问你病情,而是像你要就诊卡,这个就诊卡就记录着你之前的病史、开过的药、生病的日期,都会记录着,如果是第一次去这个医院,当然也就没有之前的病史了,但你这次的就诊也会记录在这上面。大概流程图如下:

       

       Cookie就简单介绍到这。

       客户端这边有了Cookie这个 “令牌”,那服务器这边也就需要记录 这个 “令牌” 的信息;因为一个网站,会有很多客户,大型网站无时无刻都有很多请求访问过来,那么就会带有非常多的Cookie,这也就意味着,服务器这边也要对 这些 “令牌” 进行管理,这些工作也就是下面要介绍的 Session 来负责了。

2、理解Session

       了解Session之前,我们先谈谈会话(会话:对话的意思),现实中的会话如下图:

       

       在计算机领域中,会话是一个客户端与服务器的不中断的请求响应。对于服务器来说,客户端发来的请求,服务器能识别出请求来自同一个客户端当一个未知的客户端向Web应用程序发送第一个请求,此时就开始了一个会话。当客户明确结束会话或者服务器在一个时限(时间阈值,Session默认的超时时间是30min,但这也是可以进行设置)没有接收到客户端发来的任何请求,此时会话就结束了

有点像打电话咨询客服,每次打一个电话,就会有客服和我们进行沟通,此时会话就建立了,当我们挂断电话,此时会话就会结束,或者较长时间没有回客服,没有新的请求,此时会话也会结束。

       服务器同一时刻会收到很多请求,服务器也需要清楚的区分每个请求是从属于哪个用户,也就是会有不同的会话要进行区分这些会话,就需要在服务器这边记录每个会话以及与用户信息的对应关系,服务器为了保存用户信息创建了一个特殊的对象:Session。大概流程图如下:

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

       SessionId 是由服务器生成的一个 “唯一性字符串”,从Session机制的角度来看,这个唯一性字符串称为 “SessionId”。但是站在整个登录流程中看待,也可以把这个唯一性字符串称为:“token”。

       上述例子中的令牌ID,就可以看做是SessionId,只不过令牌除了 ID 之外,还会带一些其他信息,比如时间、签名等。

   举个账户余额的例子,如图:

       Cookie和Session搭配一起使用,大概流程如下:

1、当用户登录的时候,服务器在Session会新增一个新记录,并把SessionID,返回给客户端(通过HTTP响应中是Set-Cookie字段返回)

2、客户端后续再给服务器发送请求的时候,需要在请求中带上SessionId(通过HTTP请求中的Cookie字段带上)

3、服务器接收到请求后,根据请求中的SessionId,找到对应的Session中,获取到对应的用户信息,再进行后续的操作。如果找不到,就重新创建Session,再把SessionId返回给客户端

注意Session默认是保存在内存中的,如果重启服务器,Session数据就像消失

3、Cookie 和 Session 的区别(面试常考)

(1)Cookie是客户端保存用户信息的一种机制,Session是服务器保存用户信息的一种机制

(2)Cookie和Session之间是通过SessionId关联起来的(并没有什么直接关系),SessionId是Cookie和Session之间的桥梁

(3)Cookie和Session经常会搭配在一起使用,但不是必须搭配的

      a、完全可以用Cookie保存一些数据在客户端;这些数据并不一定是用户身份信息(SessionId)

       b、Session的SessionId也不是非得通过Cookie / Set-Cookie传递,也有其他方式,比如通过URL传递

4、获取Cookie

(1)传统获取Cookie

       代码如下:

@RestController
@RequestMapping("/d1")
public class Demo1 {
    @RequestMapping("/getC1")
    public String getCookie(HttpServletRequest request, HttpServletResponse response) {
        //获取参数
        //String name = request.getParameter("name");
        //获取所有参数
        Cookie[] cookies = request.getCookies();
 
        //1、不使用lambda表达式
        StringBuilder stringBuilder = new StringBuilder();
        if(cookies != null) {
            for(Cookie ck : cookies) {
                stringBuilder.append(ck.getName() + ":" + ck.getValue());
            }
        }
        //return "获取Cookie信息:" + stringBuilder;
        
        //2、使用lambda表达式
        if(cookies != null) {
            Arrays.stream(cookies).forEach(ck -> System.out.println(ck.getName() + ":" + ck.getValue()));
        }
        return "获取Cookie";
    }
}

       使用浏览器访问:http:127.0.0.1:8080/d1/getC1,页面如下:

       

       因为没有设置Cookie,现在Cookie是null,控制台也不会打印Cookie,如图:

       现在在浏览器手动设置一些Cookie,如图:

        这个称为:host domain

       也可以使用Postman设置Cookie,如图:

       刷新一下页面,再看看控制台,打印了hahaha:666,说明后端接收到了浏览器发来的Cookie,如图:

       从这个例子也能看出来,Cookie是可以伪造的,也就是不安全的,所以使用Cookie时,后端也需要进行Cookie的校验。

1、Spring MVC是基于Servlet API构建的原始Web框架,也是在Servlet的基础上实现的,HttpServletRequest、HttpServletResponse 是Servlet提供的两个类,是Spring MVC方法的内置对象。需要时直接在方法中添加声明即可(例如注解@CookieValue,下面会介绍)

2、HttpServletRequest 对象代表客户端的请求。当客户端通过HTTP协议访问服务器时,HTTP请求头的所有信息都封装在这个对象中,通过这个对象提供的方法,可以获取到客户端请求的所有信息

3、HttpServletResponse 对象代表服务器的响应。HTTP响应的信息都在这个对象中,比如向客户端发送的数据、响应头、状态码等等。通过这个对象提供的方法,可以获得服务器响应的所有内容

       Spring MVC在这两个对象的基础上进行了封装,给我们提供了更简单的使用方法(使用注解)。下面介绍简洁获取Cookie的使用方法。

(2)简洁获取Cookie

       后端代码如下:

    @RequestMapping("/getC2")
    public String getCookie2(@CookieValue("name") String newName) {
        return "从Cookie中获取值,name:" + newName;
    }

       Cookie如下:

       浏览器访问:http:127.0.0.1:8080/d1/getC2 ,页面如下:

       

5、获取Session

(1)Session 存储

       因为Session是服务器这边存储的信息,所以要获取到到Session前要先有它。

       Session也是基于HttpServletRequest来存储和获取的,下面是存储Session的后端代码:

    @RequestMapping("/setSess")
    public String setSess(HttpServletRequest request) {
        //从Cookie中获取到SessionId,根据SessionId获取Session对象,如果没有,就会创建一个
        HttpSession session = request.getSession();
        session.setAttribute("name", "zhangsan");
        return "设置Session成功";
    }

       这个代码中虽然看不到SessionId这样的概念,但是getSession操作内部会提取到请求中的Cookie的SessionId,然后根据SessionId获取到对应的Session对象,Session对象用HttpSession来描述。如图:

       运行代码后浏览器页面如下:

       可以看到Cookie多了一个,就是我们刚才设置的,再看看Postman页面:

       也是多了一个,和浏览器一样的Cookie。

       通过fiddler抓包观察,如图:

(2)传统获取Session

       获取Session有两种方式,getSession的不同参数有两种情况,如下两种:

HttpSession getSession(boolean create);
HttpSession getSession();

HttpSession getSession(boolean create),参数如果为true,则当不存在会话是,会新建会话;参数如果不为false,则当不存在会话时,返回null,不新建会话。

       后端代码如下:

    @RequestMapping("getSess1")
    public String getsSess(HttpServletRequest request) {
        //从cookie中获取到了sessionID, 根据sessionID获取Session对象取Session对象,如果session不存在,不会自动创建
        HttpSession session = request.getSession(false);
        String userName = (String) session.getAttribute("name");
        return "name: " + userName;
    }

       Object getAttribute(String name):返回该session会话中具有指定名称的对象,如果没有指定名称的对象,则返回 null。

       前面我们已经存储了Session:session.setAttribute("name", "zhangsan");  

       现在获取一下session,浏览器访问:http:127.0.0.1:8080/d1/getSess1 ,页面如下:

       

       Postman页面如下:

       

       通过fiddler抓包进行观察,如图:

       

       可以看到,客户端发送HTTP请求时,SessionId通过Cookie传递给了服务器。

       这里如果我们修改一下Cookie的值,就会拿不到了,如图:

       原来的:

       修改后的:

       因为修改了Cookie,也就是伪造的,Cookie里的SessionId也就会改变,但服务器这边没有这个对应的SessionId,就拿不到Session了。

       

(3)简洁获取 Session(1)

       后端代码如下:

    @RequestMapping("getSess2")
    public String getSess2(HttpSession session) {
        String name = (String)session.getAttribute("name");
        return "从Session中获取name: " + name;
    }

       这里封装了 HttpSession session = Request.getSession(); 如果Session不存在,会自动创建。

       Session是放在内存中的,因为重启了程序,就要重新存储Session,浏览器要再访问一下http:127.0.0.1:8080/d1/setSess ,如下:

       浏览器访问:http:127.0.0.1:8080/d1/getSess2,页面如下:

       

(4)简洁获取 Session(2)

       后端代码如下:

    @RequestMapping("getSess3")
    public String getSess3(@SessionAttribute("name") String name) {
        return "从Session中获取name: " + name;
    }

       浏览器访问http:127.0.0.1:8080/d1/getSess3 ,页面如下:

       

下面讨论一下Spring从传统获取Session到简洁获取Session:

       如图:

       可以看到,因为getSess1方法第一行代码是有可能会写的,为了简洁方便,就给他进行了一次封装,把HttpSession对象放进参数里,但开发者觉得还不够,又进一步进行封装,省去了会重复写的代码,就是使用了注解的getSess3方法了


十一、获取Header


1、传统获取Header

       后端代码如下:

    @RequestMapping("getHeader1")
    public String getHeader1(HttpServletRequest request) {
        String userAgent = request.getHeader("User-Agent");
        return "从Header获取信息,userAgent:" + userAgent;
    }

       浏览器页面如下:

       我们使用fiddler抓包看看:

       可以看到,和请求的Header报头一样。

2、简洁获取Header

       后端代码如下:

    @RequestMapping("getHeader2")
    public String getHeader2(@RequestHeader("User-Agent") String userAgent) {
        return "从Header获取信息,userAgent:" + userAgent;
    }

       浏览器页面如下:

       可以看到,响应和上面的一样,简洁的写法就是Spring对传统的写法进行了封装,使代码更简单、易学。

相关文章
|
15天前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
31 4
|
5天前
|
前端开发 Java 数据库
SpringBoot入门(3) - 对Hello world进行MVC分层
SpringBoot入门(3) - 对Hello world进行MVC分层
18 1
SpringBoot入门(3) - 对Hello world进行MVC分层
|
3天前
|
前端开发 Java 数据库
SpringBoot入门(3) - 对Hello world进行MVC分层
本文介绍了如何在Spring Boot项目中实现MVC分层架构,通过将代码划分为controller、service、dao和entity四个部分,实现高内聚低耦合的设计。示例项目包括用户增删查改功能,详细展示了各层的具体实现及运行测试。
23 11
|
3天前
|
前端开发 Java 数据库
SpringBoot入门(3) - 对Hello world进行MVC分层
SpringBoot入门(3) - 对Hello world进行MVC分层
9 2
|
18天前
|
Java API Spring
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中拦截器的入门教程和实战项目场景实现的详细指南。
14 0
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
|
18天前
|
Java API Spring
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中过滤器的基础知识和实战项目应用的教程。
16 0
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
|
3天前
|
前端开发 开发者
WEB自定义页面请求响应
Web组件支持在应用拦截到页面请求后自定义响应请求能力。开发者通过onInterceptRequest()接口来实现自定义资源请求响应 。自定义请求能力可以用于开发者自定义Web页面响应、自定义文件资源响应等场景。
|
2月前
|
SQL 存储 安全
Web安全-CSRF跨站请求伪造
Web安全-CSRF跨站请求伪造
65 5
|
2月前
|
前端开发 安全 Java
技术进阶:使用Spring MVC构建适应未来的响应式Web应用
【9月更文挑战第2天】随着移动设备的普及,响应式设计至关重要。Spring MVC作为强大的Java Web框架,助力开发者创建适应多屏的应用。本文推荐使用Thymeleaf整合视图,通过简洁的HTML代码提高前端灵活性;采用`@ResponseBody`与`Callable`实现异步处理,优化应用响应速度;运用`@ControllerAdvice`统一异常管理,保持代码整洁;借助Jackson简化JSON处理;利用Spring Security增强安全性;并强调测试的重要性。遵循这些实践,将大幅提升开发效率和应用质量。
62 7
|
2月前
|
前端开发 测试技术 开发者
MVC模式在现代Web开发中有哪些优势和局限性?
MVC模式在现代Web开发中有哪些优势和局限性?