在项目中使用Apache XML-RPC时,有时候需要获得客户端的ip,以便于记录日志等,由于官方没有提供相应的方法,也没有对其做实现,所以需要手工修改源码来实现该功能。XML-RPC本身是一个Servlet,所以要获得调用者ip,可以在Servlet的调用入口处doGet或doPost方法中获取,获取到以后还需要将其存储起来,并提供一个接口供外部调用,可以考虑用ThreadLocal来存储,并提供一个public static的方法供外部调用获取ip。
具体实现方法:
下载与当前版本对应的源码,并将源码拷贝到项目src下面,同时删除lib下相应的jar包,最新的版本是3.1.3,下载地址是:http://labs.renren.com/apache-mirror//ws/xmlrpc/apache-xmlrpc-current-src.zip 。
修改源码:
找到org.apache.xmlrpc.webserver包下面的XmlRpcServlet类,在该类里面添加私有变量
private static ThreadLocal clientIpAddress = new ThreadLocal();
和供外部调用的接口
public static String getClientIpAddress() { return (String) clientIpAddress.get(); }
在doPost方法里面,添加获取并设置ip的语句clientIpAddress.set(pRequest.getRemoteAddr());
public void doPost(HttpServletRequest pRequest, HttpServletResponse pResponse) throws IOException, ServletException { clientIpAddress.set(pRequest.getRemoteAddr()); server.execute(pRequest, pResponse); }
至此,就完成了,外部可通过调用XmlRpcServlet.getClientIpAddress()方法来获取IP了
附修改后的源码,版本不同可能有细微差异:
/* * Copyright 1999,2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.xmlrpc.webserver; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.util.Enumeration; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.xmlrpc.XmlRpcConfig; import org.apache.xmlrpc.XmlRpcException; import org.apache.xmlrpc.common.TypeConverterFactory; import org.apache.xmlrpc.server.AbstractReflectiveHandlerMapping; import org.apache.xmlrpc.server.PropertyHandlerMapping; import org.apache.xmlrpc.server.RequestProcessorFactoryFactory; import org.apache.xmlrpc.server.XmlRpcHandlerMapping; import org.apache.xmlrpc.server.XmlRpcServer; import org.apache.xmlrpc.util.ReflectionUtil; /** <p>A default servlet implementation The typical use would * be to derive a subclass, which is overwriting at least the * method {@link #newXmlRpcHandlerMapping()}.</p> * <p>The servlet accepts the following init parameters: * <table border="1"> * <tr><th>Name</th><th>Description</th></tr> * <tr><td>enabledForExtensions</td><td>Sets the value * {@link XmlRpcConfig#isEnabledForExtensions()} * to true.</td></tr> * </table> * </p> */ public class XmlRpcServlet extends HttpServlet { private static final long serialVersionUID = 2348768267234L; private static final Log log = LogFactory.getLog(XmlRpcServlet.class); private XmlRpcServletServer server; private AbstractReflectiveHandlerMapping.AuthenticationHandler authenticationHandler; private RequestProcessorFactoryFactory requestProcessorFactoryFactory; private TypeConverterFactory typeConverterFactory; private static ThreadLocal clientIpAddress = new ThreadLocal(); /** Returns the servlets instance of {@link XmlRpcServletServer}. * @return The configurable instance of {@link XmlRpcServletServer}. */ public XmlRpcServletServer getXmlRpcServletServer() { return server; } public static String getClientIpAddress() { return (String) clientIpAddress.get(); } private void handleInitParameters(ServletConfig pConfig) throws ServletException { for (Enumeration en = pConfig.getInitParameterNames(); en.hasMoreElements(); ) { String name = (String) en.nextElement(); String value = pConfig.getInitParameter(name); try { if (!ReflectionUtil.setProperty(this, name, value) && !ReflectionUtil.setProperty(server, name, value) && !ReflectionUtil.setProperty(server.getConfig(), name, value)) { throw new ServletException("Unknown init parameter " + name); } } catch (IllegalAccessException e) { throw new ServletException("Illegal access to instance of " + server.getClass().getName() + " while setting property " + name + ": " + e.getMessage(), e); } catch (InvocationTargetException e) { Throwable t = e.getTargetException(); throw new ServletException("Failed to invoke setter for property " + name + " on instance of " + server.getClass().getName() + ": " + t.getMessage(), t); } } } public void init(ServletConfig pConfig) throws ServletException { super.init(pConfig); try { server = newXmlRpcServer(pConfig); handleInitParameters(pConfig); server.setHandlerMapping(newXmlRpcHandlerMapping()); } catch (XmlRpcException e) { try { log("Failed to create XmlRpcServer: " + e.getMessage(), e); } catch (Throwable ignore) { } throw new ServletException(e); } } /** Sets the servlets {@link AbstractReflectiveHandlerMapping.AuthenticationHandler}. */ public void setAuthenticationHandler(AbstractReflectiveHandlerMapping.AuthenticationHandler pHandler) { authenticationHandler = pHandler; } /** Returns the servlets {@link AbstractReflectiveHandlerMapping.AuthenticationHandler}. */ public AbstractReflectiveHandlerMapping.AuthenticationHandler getAuthenticationHandler() { return authenticationHandler; } /** Sets the servlets {@link RequestProcessorFactoryFactory}. */ public void setRequestProcessorFactoryFactory(RequestProcessorFactoryFactory pFactory) { requestProcessorFactoryFactory = pFactory; } /** Returns the servlets {@link RequestProcessorFactoryFactory}. */ public RequestProcessorFactoryFactory getRequestProcessorFactoryFactory() { return requestProcessorFactoryFactory; } /** Sets the servlets {@link TypeConverterFactory}. */ public void setTypeConverterFactory(TypeConverterFactory pFactory) { typeConverterFactory = pFactory; } /** Returns the servlets {@link TypeConverterFactory}. */ public TypeConverterFactory getTypeConverterFactory() { return typeConverterFactory; } /** Creates a new instance of {@link XmlRpcServer}, * which is being used to process the requests. The default implementation * will simply invoke <code>new {@link XmlRpcServer}. */ protected XmlRpcServletServer newXmlRpcServer(ServletConfig pConfig) throws XmlRpcException { return new XmlRpcServletServer(); } /** Creates a new handler mapping. The default implementation loads * a property file from the resource * <code>org/apache/xmlrpc/webserver/XmlRpcServlet.properties</code> */ protected XmlRpcHandlerMapping newXmlRpcHandlerMapping() throws XmlRpcException { URL url = XmlRpcServlet.class.getResource("XmlRpcServlet.properties"); if (url == null) { throw new XmlRpcException("Failed to locate resource XmlRpcServlet.properties"); } try { return newPropertyHandlerMapping(url); } catch (IOException e) { throw new XmlRpcException("Failed to load resource " + url + ": " + e.getMessage(), e); } } /** Creates a new instance of {@link PropertyHandlerMapping} by * loading the property file from the given URL. Called from * {@link #newXmlRpcHandlerMapping()}. */ protected PropertyHandlerMapping newPropertyHandlerMapping(URL url) throws IOException, XmlRpcException { PropertyHandlerMapping mapping = new PropertyHandlerMapping(); mapping.setAuthenticationHandler(authenticationHandler); if (requestProcessorFactoryFactory != null) { mapping.setRequestProcessorFactoryFactory(requestProcessorFactoryFactory); } if (typeConverterFactory != null) { mapping.setTypeConverterFactory(typeConverterFactory); } else { mapping.setTypeConverterFactory(server.getTypeConverterFactory()); } mapping.setVoidMethodEnabled(server.getConfig().isEnabledForExtensions()); mapping.load(Thread.currentThread().getContextClassLoader(), url); return mapping; } /** Creates a new instance of {@link org.apache.xmlrpc.webserver.RequestData} * for the request. */ public void doPost(HttpServletRequest pRequest, HttpServletResponse pResponse) throws IOException, ServletException { // String ip = IPUtils.getIpAddr(pRequest); // System.out.println("RPC-XmlRpcServlet,clientIP: " + ip); clientIpAddress.set(pRequest.getRemoteAddr()); server.execute(pRequest, pResponse); } public void log(String pMessage, Throwable pThrowable) { log.error(pMessage, pThrowable); } public void log(String pMessage) { log.info(pMessage); } }