spring mvc 中可不可以在controller中进行初始化

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring mvc 中可不可以在controller中进行初始化相关的知识,希望对你有一定的参考价值。

一般都不会这么做的,初始化就在启动时候或者在拦截器也可以,但是在控制层的,没有试过,因为控制层需要请求时才生效 手动在spring配置文件中配置一下呢?然后配置一下初始化Bean的时候,执行指定的方法,应该也可以吧。 参考技术A 一般都不会这么做的,初始化就在启动时候或者在拦截器也可以,但是在控制层的,没有试过,因为控制层需要请求时才生效
手动在spring配置文件中配置一下呢?然后配置一下初始化Bean的时候,执行指定的方法,应该也可以吧。

如何在 Spring MVC Controller get call 中提取 IP 地址?

【中文标题】如何在 Spring MVC Controller get call 中提取 IP 地址?【英文标题】:How to extract IP Address in Spring MVC Controller get call? 【发布时间】:2014-05-17 15:01:33 【问题描述】:

我正在开发 Spring MVC 控制器项目,在该项目中我正在从浏览器进行 GET URL 调用 -

下面是我从浏览器发出 GET 调用的 url -

http://127.0.0.1:8080/testweb/processing?workflow=test&conf=20140324&dc=all

下面是点击浏览器后调用的代码 -

@RequestMapping(value = "processing", method = RequestMethod.GET)
public @ResponseBody ProcessResponse processData(@RequestParam("workflow") final String workflow,
    @RequestParam("conf") final String value, @RequestParam("dc") final String dc) 

        System.out.println(workflow);
        System.out.println(value);
        System.out.println(dc);

        // some other code
    

问题陈述:-

现在有什么方法可以从某个标头中提取 IP 地址吗?这意味着我想知道来自哪个 IP 地址的呼叫,这意味着无论是谁在 URL 上方呼叫,我都需要知道他们的 IP 地址。这可以吗?

【问题讨论】:

尝试使用 Spring AOP 并处理 HttpServletRequest。 ***.com/questions/19271807/… 【参考方案1】:

解决办法是

@RequestMapping(value = "processing", method = RequestMethod.GET)
public @ResponseBody ProcessResponse processData(@RequestParam("workflow") final String workflow,
    @RequestParam("conf") final String value, @RequestParam("dc") final String dc, HttpServletRequest request) 

        System.out.println(workflow);
        System.out.println(value);
        System.out.println(dc);
        System.out.println(request.getRemoteAddr());
        // some other code
    

HttpServletRequest request 添加到您的方法定义中,然后使用 Servlet API

Spring 文档here 中说

15.3.2.3 支持的处理程序方法参数和返回类型

Handler methods that are annotated with @RequestMapping can have very flexible signatures.
Most of them can be used in arbitrary order (see below for more details).

Request or response objects (Servlet API). Choose any specific request or response type,
for example ServletRequest or HttpServletRequest

【讨论】:

感谢 Koitoer 的帮助。一个快速的问题,假设如果呼叫来自负载均衡器而不是特定机器,那么这也可以吗?我猜不是.. 不,它不会,但是负载均衡器中有一些配置可以发送IP,因为它们不存在,可能是你的情况 检查负载均衡器是否可以在标头中发送这些值,因此请考虑使用 HttpServletRequest 的 getHeader 方法。 Koitoer 完美运行!!但是除了 HttpServletRequest 之外,还有其他方法。 已弃用。【参考方案2】:

我来晚了,但这可能有助于寻找答案的人。通常servletRequest.getRemoteAddr() 有效。

在许多情况下,您的应用程序用户可能通过代理服务器访问您的网络服务器,或者您的应用程序可能位于负载平衡器后面。

所以你应该在这种情况下访问X-Forwarded-For http header 来获取用户的IP地址。

例如String ipAddress = request.getHeader("X-FORWARDED-FOR");

希望这会有所帮助。

【讨论】:

请注意,X-Forwarded-For 通常是一个以逗号分隔的 ips 列表,链中的每个代理都将它看到的远程地址添加到列表中。因此,一个好的实现通常会有一个受信任的代理列表,并在从右到左读取此标头时“跳过”这些 ip。 如何获取ip地址为111.111.111.111/X 请注意,例如Tomcat 有 RemoteIpValve 解析 X-Forwarded-For 标头并将其设置在 HttpServletRequest 上,以便 servletRequest.getRemoteAddr() 返回正确的最终用户 IP 地址。在 Spring Boot 中,可以通过 server.tomcat.remote-ip-header=X-Forwarded-For 应用程序属性启用它 X-FORWARDED-FOR 标头不能被客户端欺骗吗?如果getRemoteAddr() 属于可信代理服务提供商的白名单,则仅假设X-FORWARDED-FOR 有效不是更安全吗? Spring boot 能够为你自动解析转发的IP地址。详情请见this question。【参考方案3】:

我就是用这种方法来做的

public class HttpReqRespUtils 

    private static final String[] IP_HEADER_CANDIDATES = 
        "X-Forwarded-For",
        "Proxy-Client-IP",
        "WL-Proxy-Client-IP",
        "HTTP_X_FORWARDED_FOR",
        "HTTP_X_FORWARDED",
        "HTTP_X_CLUSTER_CLIENT_IP",
        "HTTP_CLIENT_IP",
        "HTTP_FORWARDED_FOR",
        "HTTP_FORWARDED",
        "HTTP_VIA",
        "REMOTE_ADDR"
    ;

    public static String getClientIpAddressIfServletRequestExist() 

        if (RequestContextHolder.getRequestAttributes() == null) 
            return "0.0.0.0";
        

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        for (String header: IP_HEADER_CANDIDATES) 
            String ipList = request.getHeader(header);
            if (ipList != null && ipList.length() != 0 && !"unknown".equalsIgnoreCase(ipList)) 
                String ip = ipList.split(",")[0];
                return ip;
            
        

        return request.getRemoteAddr();
    

【讨论】:

我在哪里使用它? 是一个静态类,它使用类名和方法ip = HttpReqRespUtils.getClientIpAddressIfServletRequestExist(); 对于那些想知道为什么在RequestContextHolder.getRequestAttributes() == null 时返回0.0.0.0 的人,请参阅0.0.0.0 - Wikipedia。 在上述代码中的return ip语句之前添加if (ip.equals("0:0:0:0:0:0:0:1")) ip = "127.0.0.1";,使其能够投诉IPv4。【参考方案4】:

您可以从RequestContextHolder 静态获取IP 地址,如下所示:

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
        .getRequest();

String ip = request.getRemoteAddr();

【讨论】:

【参考方案5】:

在我的例子中,我在我的应用程序前面使用了 Nginx,配置如下:

location / 
     proxy_pass        http://localhost:8080/;
     proxy_set_header  X-Real-IP $remote_addr;
     proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_set_header  Host $http_host;
     add_header Content-Security-Policy 'upgrade-insecure-requests';

所以在我的应用程序中,我得到了真正的用户 ip,如下所示:

String clientIP = request.getHeader("X-Real-IP");

【讨论】:

【参考方案6】:

下面是Spring方式,autowired请求bean在@Controller类中:

@Autowired 
private HttpServletRequest request;

System.out.println(request.getRemoteHost());

【讨论】:

这可能会导致跨多个线程并发使用控制器时出现问题。只能使用 @Autowired 将单例注入到 @Controller 实例中。否则,您必须在控制器类上使用@Scope(BeanDefinition.SCOPE_PROTOTYPE) 以确保每次请求都会生成控制器的新实例。这效率较低,但如果您必须将某些东西作为属性注入控制器类,这是一种解决方法。【参考方案7】:

将此方法放入您的 BaseController 中:

@SuppressWarnings("ConstantConditions")
protected String fetchClientIpAddr() 
    HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.getRequestAttributes())).getRequest();
    String ip = Optional.ofNullable(request.getHeader("X-FORWARDED-FOR")).orElse(request.getRemoteAddr());
    if (ip.equals("0:0:0:0:0:0:0:1")) ip = "127.0.0.1";
    Assert.isTrue(ip.chars().filter($ -> $ == '.').count() == 3, "Illegal IP: " + ip);
    return ip;

【讨论】:

【参考方案8】:

见下文。此代码适用于 spring-boot 和 spring-boot + apache CXF/SOAP。

    // in your class RequestUtil
    private static final String[] IP_HEADER_NAMES =  
                                                        "X-Forwarded-For",
                                                        "Proxy-Client-IP",
                                                        "WL-Proxy-Client-IP",
                                                        "HTTP_X_FORWARDED_FOR",
                                                        "HTTP_X_FORWARDED",
                                                        "HTTP_X_CLUSTER_CLIENT_IP",
                                                        "HTTP_CLIENT_IP",
                                                        "HTTP_FORWARDED_FOR",
                                                        "HTTP_FORWARDED",
                                                        "HTTP_VIA",
                                                        "REMOTE_ADDR"
                                                    ;

    public static String getRemoteIP(RequestAttributes requestAttributes)
    
        if (requestAttributes == null)
        
            return "0.0.0.0";
        
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        String ip = Arrays.asList(IP_HEADER_NAMES)
            .stream()
            .map(request::getHeader)
            .filter(h -> h != null && h.length() != 0 && !"unknown".equalsIgnoreCase(h))
            .map(h -> h.split(",")[0])
            .reduce("", (h1, h2) -> h1 + ":" + h2);
        return ip + request.getRemoteAddr();
    

    //... in service class:
    String remoteAddress = RequestUtil.getRemoteIP(RequestContextHolder.currentRequestAttributes());

:)

【讨论】:

【参考方案9】:
private static final String[] IP_HEADER_CANDIDATES = 
            "X-Forwarded-For",
            "Proxy-Client-IP",
            "WL-Proxy-Client-IP",
            "HTTP_X_FORWARDED_FOR",
            "HTTP_X_FORWARDED",
            "HTTP_X_CLUSTER_CLIENT_IP",
            "HTTP_CLIENT_IP",
            "HTTP_FORWARDED_FOR",
            "HTTP_FORWARDED",
            "HTTP_VIA",
            "REMOTE_ADDR"
    ;

    public static String getIPFromRequest(HttpServletRequest request) 
        String ip = null;
        if (request == null) 
            if (RequestContextHolder.getRequestAttributes() == null) 
                return null;
            
            request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        

        try 
            ip = InetAddress.getLocalHost().getHostAddress();
         catch (Exception e) 
            e.printStackTrace();
        
        if (!StringUtils.isEmpty(ip))
            return ip;

        for (String header : IP_HEADER_CANDIDATES) 
            String ipList = request.getHeader(header);
            if (ipList != null && ipList.length() != 0 && !"unknown".equalsIgnoreCase(ipList)) 
                return ipList.split(",")[0];
            
        

        return request.getRemoteAddr();
    

在大多数情况下,我将上面的代码与此代码相结合。将您从 api 获得的 HttpServletRequest request 传递给方法

【讨论】:

【参考方案10】:

就我而言,我正在使用这段代码:

private String getRemoteAddr(HttpServletRequest req) 
    if (!StringUtils.isEmpty(req.getHeader("X-Real-IP"))) 
        return req.getHeader("X-Real-IP");
    
    return req.getRemoteAddr();

【讨论】:

以上是关于spring mvc 中可不可以在controller中进行初始化的主要内容,如果未能解决你的问题,请参考以下文章

spring mvc 中quartz 怎么去定时调用controller

Spring MVC Controller中JsonView的动态选择

Spring 3 MVC Controller 集成测试 - 将 Principal 注入方法

Spring Mvc——Controller中常规方法示例

Spring MVC 常用注解@Controller,@RequestMapping,Model和ModelAndView

Spring MVC @Controller中返回值为void类型