原文网址: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();
    }
}

法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);
    }
}

法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();
    }
}

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐