当前位置: 首页 > news >正文

SpringBoot--Controller获取HttpServletRequest

原文网址:SpringBoot--Controller获取HttpServletRequest_IT利刃出鞘的博客-CSDN博客

简介

        本文介绍SpringBoot如何在Controller中获取HttpServletRequest。

法1:Controller中加参数

简介

        该方法实现的原理是,在Controller方法开始处理请求时,Spring会将request对象赋值到方法参数中。除了request对象,可以通过这种方法获取的参数还有很多。

        Controller中获取request对象后,如果要在其他方法中(如service方法、工具类方法等)使用request对象,需要在调用这些方法时将request对象作为参数传入。

代码示例

这种方法实现最简单,直接上Controller代码:

​package com.example.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

@RestController
@RequestMapping
public class HelloController {

    @GetMapping("/test1")
    public String test1(HttpServletRequest request) {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(request);
        return request.toString();
    }
}

线程安全性

是线程安全的。

测试:接口中睡眠,模拟多个请求同时处理

直接用“代码示例”中的代码

Postman开两个窗口,都访问:http://localhost:8080/test1

结果:(两个不同的request,可见线程安全的)

org.apache.catalina.connector.RequestFacade@4613eaaa
org.apache.catalina.connector.RequestFacade@492b9e2e

注意:如果不加睡眠,结果可能是:两个相同的request,因为如果它能处理过来,就会用同一个request去接收了。

法2:自动注入

代码示例

package com.example.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

@RestController
@RequestMapping
public class HelloController {
    @Autowired
    private HttpServletRequest request;

    @GetMapping("/test1")
    public String test1() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(request);
        return request.toString();
    }
}

线程安全性

        线程安全(不是测出来的,是看代码得出的)。

        分析:在Spring中,Controller的scope是singleton(单例),也就是说在整个web系统中,只有一个TestController;但是其注入的request却是线程安全的。

测试:接口中睡眠,模拟多个请求同时处理

使用上边“代码示例”中的代码

Postman开两个窗口,都访问:http://localhost:8080/test1

结果:(这个结果很奇怪,只能去追寻源码。见:SpringMVC原理--Controller线程安全_IT利刃出鞘的博客-CSDN博客)

Current HttpServletRequest
Current HttpServletRequest

法3:基类中自动注入

说明

        与方法2相比,将注入部分代码放入到了基类中。

代码示例

基类代码

public class BaseController {
    @Autowired
    protected HttpServletRequest request;     
}

Controller代码

        这里列举了BaseController的两个派生类,由于此时测试代码会有所不同,因此服务端测试代码没有省略;客户端也需要进行相应的修改(同时向2个url发送大量并发请求)。

@Controller
public class TestController extends BaseController {
    // 存储已有参数,用于判断参数value是否重复,从而判断线程是否安全
    public static Set<String> set = new ConcurrentSkipListSet<>();
    @RequestMapping("/test")
    public void test() throws InterruptedException {
        String value = request.getParameter("key");
        // 判断线程安全
        if (set.contains(value)) {
            System.out.println(value + "\t重复出现,request并发不安全!");
        } else {
            System.out.println(value);
            set.add(value);
        }
        // 模拟程序执行了一段时间
        Thread.sleep(1000);
    }
}
@Controller
public class Test2Controller extends BaseController {
    @RequestMapping("/test2")
    public void test2() throws InterruptedException {
        String value = request.getParameter("key");
        // 判断线程安全(与TestController使用一个set进行判断)
        if (TestController.set.contains(value)) {
            System.out.println(value + "\t重复出现,request并发不安全!");
        } else {
            System.out.println(value);
            TestController.set.add(value);
        }
        // 模拟程序执行了一段时间
        Thread.sleep(1000);
    }
}

线程安全性

测试结果:线程安全

分析:在理解了方法2的线程安全性的基础上,很容易理解方法3是线程安全的:当创建不同的派生类对象时,基类中的域(这里是注入的request)在不同的派生类对象中会占据不同的内存空间,也就是说将注入request的代码放在基类中对线程安全性没有任何影响;测试结果也证明了这一点。

优缺点

        与方法2相比,避免了在不同的Controller中重复注入request;但是考虑到java只允许继承一个基类,所以如果Controller需要继承其他类时,该方法便不再好用。

        无论是方法2和方法3,都只能在Bean中注入request;如果其他方法(如工具类中static方法)需要使用request对象,则需要在调用这些方法时将request参数传递进去。下面介绍的方法4,则可以直接在诸如工具类中的static方法中使用request对象(当然在各种Bean中也可以使用)。

法4:@ModelAttribute

代码示例

下面这种方法及其变种(变种:将request和bindRequest放在子类中)在网上经常见到:

package com.example.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

@RestController
@RequestMapping
public class HelloController {
    protected HttpServletRequest request;

    @ModelAttribute
    public void bindreq(HttpServletRequest request) {
        this.request = request;
    }

    @GetMapping("/test1")
    public String test1() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(request);
        return request.toString();
    }
}

线程安全性

        是线程安全的。

        分析:@ModelAttribute注解用在Controller中修饰方法时,其作用是Controller中的每个@RequestMapping方法执行前,该方法都会执行。因此在本例中,bindRequest()的作用是在test()执行前为request对象赋值。

测试:接口中睡眠,模拟多个请求同时处理

使用上边“代码示例”中的代码

Postman开两个窗口,都访问:http://localhost:8080/test1

结果:(虽然结果是同一个request,但是是线程安全的。跟“注入request”类似)。

org.apache.catalina.connector.RequestFacade@3bb8d854
org.apache.catalina.connector.RequestFacade@3bb8d854

相关文章:

  • 牛客刷题笔记
  • 我把华为云的Ubuntu 18.04升级到了Ubuntu 22.04
  • Google Earth Engine-02(主界面介绍)
  • 5.java数据结构与算法 ---- 第七章 八大排序(冒泡;选择;插入/希尔;快排;归并;基数)
  • 新学期你立一个什么样的FLAG?
  • 【数据结构与算法】第九篇:哈希表原理
  • 自动驾驶江湖重新排位:毫末智行“重感知、轻地图”优势初现
  • [JS]变量
  • 用户登录更新中:网关,token,全局异常处理
  • Unity Pico Neo3 基础开发流程
  • 图的刷题..
  • 机器学习个人总结(王道版)
  • 【Machine Learning】8.逻辑回归及其在分类问题的应用
  • ZYNQ之路--带你弄明白Vivado设计流程
  • 最大子数组和-前缀和/动态规划/分治/暴力-Java/c++
  • CSS居中完全指南——构建CSS居中决策树
  • CSS中外联样式表代表的含义
  • Effective Java 笔记(一)
  • JavaScript学习总结——原型
  • LeetCode29.两数相除 JavaScript
  • mysql innodb 索引使用指南
  • nodejs调试方法
  • PAT A1050
  • React 快速上手 - 07 前端路由 react-router
  • 爱情 北京女病人
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 好的网址,关于.net 4.0 ,vs 2010
  • 目录与文件属性:编写ls
  • 温故知新之javascript面向对象
  • 我的面试准备过程--容器(更新中)
  • MiKTeX could not find the script engine ‘perl.exe‘ which is required to execute ‘latexmk‘.
  • No resource identifier found for attribute,RxJava之zip操作符
  • 阿里云重庆大学大数据训练营落地分享
  • 湖北分布式智能数据采集方法有哪些?
  • # 学号 2017-2018-20172309 《程序设计与数据结构》实验三报告
  • #define、const、typedef的差别
  • #include到底该写在哪
  • (4)logging(日志模块)
  • (翻译)terry crowley: 写给程序员
  • (附源码)ssm考试题库管理系统 毕业设计 069043
  • (附源码)计算机毕业设计SSM基于健身房管理系统
  • (黑马出品_高级篇_01)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • (正则)提取页面里的img标签
  • (转)IIS6 ASP 0251超过响应缓冲区限制错误的解决方法
  • .Net 中Partitioner static与dynamic的性能对比
  • .NET导入Excel数据
  • .NET高级面试指南专题十一【 设计模式介绍,为什么要用设计模式】
  • .skip() 和 .only() 的使用
  • ??如何把JavaScript脚本中的参数传到java代码段中
  • [Angular 基础] - 指令(directives)
  • [asp.net core]project.json(2)
  • [autojs]autojs开关按钮的简单使用
  • [AutoSar]BSW_Com02 PDU详解
  • [C#]猫叫人醒老鼠跑 C#的委托及事件