SpringMVC中幾種獲取訪客IP的方法


核心在獲取HttpServletRequest
第一種方法:

在方法上面的參數列表里打上HttpServletRequest

    @RequestMapping(value="/index.html",method=RequestMethod.GET)
        public String index(HttpServletRequest req) {
            String remoteAddr = req.getRemoteAddr();
            System.out.println(remoteAddr);
            return "index";
        }

第二種方法:

使用@autowire自動注入HttpServletRequest對象,在controller頁面

    @Autowired
    HttpServletRequest req;


第三種方法:

使用springMVC封裝的方法得到request

    @RequestMapping(value="/index.html",method=RequestMethod.GET)
        public String index() {
            HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            String remoteAddr = req.getRemoteAddr();
            System.out.println(remoteAddr);
            return "index";
        }

注意點:

如果在本機上開發,使用http://localhost:8080/之類去訪問,會得到一串都是0的IP,把localhost改成127.0.0.1即可看到效果

如果采用nginx反向代理,需要改寫一下才能獲取到訪客的真實ip:可以寫一個如下的工具類

    package com.utils;
     
    import javax.servlet.http.HttpServletRequest;
     
    public class GetIP {
        public String getIP(HttpServletRequest request){
            String ip=request.getHeader("x-forwarded-for");
            if(ip==null || ip.length()==0 || "unknown".equalsIgnoreCase(ip)){
                ip=request.getHeader("Proxy-Client-IP");
            }
            if(ip==null || ip.length()==0 || "unknown".equalsIgnoreCase(ip)){
                ip=request.getHeader("WL-Proxy-Client-IP");
            }
            if(ip==null || ip.length()==0 || "unknown".equalsIgnoreCase(ip)){
                ip=request.getHeader("X-Real-IP");
            }
            if(ip==null || ip.length()==0 || "unknown".equalsIgnoreCase(ip)){
                ip=request.getRemoteAddr();
            }
            return ip;
        }
        
        
    }


---------------------
作者:白學家Lynn
來源:CSDN
原文:https://blog.csdn.net/Lynn_coder/article/details/79388337
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!

====================================================================================================================================

SpringMvc中獲取Request

  • Controller中加參數
  • 自動注入
  • 基類中自動注入
  • 手動調用
  • @ModelAttribute方法

 

Controller中加參數

 
@Controller
public class TestController { @RequestMapping("/test") public void test(HttpServletRequest request) { ...... } }
 

Controller中獲取request對象后,如果要在其他方法中(如service方法、工具類方法等)使用request對象,需要在調用這些方法時將request對象作為參數傳入

此時request對象是方法參數,相當於局部變量,毫無疑問是線程安全的。 

自動注入

 
@Controller
public class TestController{ @Autowired private HttpServletRequest request; //自動注入request  @RequestMapping("/test") public void test() throws InterruptedException{ ...... } }
 

使用這種方式,當Bean(本例的TestController)初始化時,Spring並沒有注入一個request對象,而是注入了一個代理(proxy);當Bean中需要使用request對象時,通過該代理獲取request對象。request實際上是一個代理:代理的實現參見AutowireUtils的內部類ObjectFactoryDelegatingInvocationHandler。

調用request的方法method時,實際上是調用了由objectFactory.getObject()生成的對象的method方法;objectFactory.getObject()生成的對象才是真正的request對象。

objectFactory的類型為WebApplicationContextUtils的內部類RequestObjectFactory;而RequestObjectFactory要獲得request對象需要先調用currentRequestAttributes()方法獲得RequestAttributes對象,生成RequestAttributes對象的核心代碼在類RequestContextHolder中,生成的RequestAttributes對象是線程局部變量(ThreadLocal),因此request對象也是線程局部變量;這就保證了request對象的線程安全性。

基類中自動注入

 
public class BaseController { @Autowired protected HttpServletRequest request; } @Controller public class TestController extends BaseController { }
 

與方法2相比,避免了在不同的Controller中重復注入request;但是考慮到java只允許繼承一個基類,所以如果Controller需要繼承其他類時,該方法便不再好用。

手動調用

 
@Controller
public class TestController { @RequestMapping("/test") public void test() throws InterruptedException { HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); ....... } }
 

通過自動注入實現與通過手動方法調用實現原理差不多。因此本方法也是線程安全的。

優點:可以在非Bean中直接獲取。缺點:如果使用的地方較多,代碼非常繁瑣;因此可以與其他方法配合使用。

@ModelAttribute方法

 
@Controller
public class TestController { private HttpServletRequest request; 此處線程不安全 @ModelAttribute public void bindRequest(HttpServletRequest request) { this.request = request; 此處request線程安全 } @RequestMapping("/test") public void test() throws InterruptedException { ...... } }
 

@ModelAttribute注解用在Controller中修飾方法時,其作用是Controller中的每個@RequestMapping方法執行前,該方法都會執行。bindRequest()的作用是在test()執行前為request對象賦值。雖然bindRequest()中的參數request本身是線程安全的,但由於TestController是單例的,request作為TestController的一個域,無法保證線程安全。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM