基于JWS的WebService的两种发布方式及获取客户端IP的方法

首先使用JAX-WS开发WebService

步骤:写接口–实现接口–发布–生成客户端(测试或者使用)
写接口
package service;

import java.util.Date;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;

/**
 * 作为测试的WebService接口
 * 
 * @author Johness
 * 
 */
@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface SayHiService {

    /**
     * 执行测试的WebService方法
     */
    @WebMethod
    void SayHiDefault();

    /**
     * 执行测试的WebService方法(有参)
     * 
     * @param name
     */
    @WebMethod
    void SayHi(@WebParam(name = "name") String name);

    /**
     * 执行测试的WebService方法(用于时间校验)
     * 
     * @param clentTime 客户端时间
     * @return 0表示时间校验失败 1表示校验成功
     */
    @WebMethod
    @WebResult(name = "valid")
    int CheckTime(@WebParam(name = "clientTime") Date clientTime);
}
实现接口
package service.imp;

import java.text.SimpleDateFormat;
import java.util.Date;

import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;

import service.SayHiService;

/**
 * 作为测试的WebService实现类
 * 
 * @author Johness
 * 
 */
@WebService(endpointInterface = "service.SayHiService")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class SayHiServiceImp implements SayHiService {

    @Override
    public void SayHiDefault() {
        System.out.println("Hi, Johness!");
    }

    @Override
    public void SayHi(String name) {
        System.out.println("Hi, " + name + "!");
    }

    @Override
    public int CheckTime(Date clientTime) {
        // 精确到秒
        String dateServer = new java.sql.Date(System.currentTimeMillis())
                .toString()
                + " "
                + new java.sql.Time(System.currentTimeMillis());
        String dateClient = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                .format(clientTime);
        return dateServer.equals(dateClient) ? 1 : 0;
    }

}
然后是发布

发布方式一般有两种:
1)以 Endpoint.publish 发布

package mian;

import javax.xml.ws.Endpoint;

import service.imp.SayHiServiceImp;

public class Main {

    /**
     * 发布WebService
     * 简单
     */
    public static void main(String[] args) {
        Endpoint.publish("http://localhost:8080/testjws/service/sayHi", new SayHiServiceImp());
    }

}

2)基于Web服务器Servlet方式发布
以Tomcat为例,首先编写 sun-jaxws.xml文件放到WEB-INF下:

<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"
    version="2.0">
    <endpoint name="SayHiService"  //接口
        implementation="service.imp.SayHiServiceImpl"  //接口实现
        url-pattern="/service/sayHi" /> //发布的url的后缀
</endpoints>

然后改动web.xml ,添加listener和servlet(url-pattern 要和sun-jaxws.xml 中的相同)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
    
    <listener>  
        <listener-class>
            com.sun.xml.ws.transport.http.servlet.WSServletContextListener  
        </listener-class>
    </listener>
    <servlet>
        <servlet-name>SayHiService</servlet-name>  
        <servlet-class>
            com.sun.xml.ws.transport.http.servlet.WSServlet  
        </servlet-class>
    </servlet>  
    <servlet-mapping>  
        <servlet-name>SayHiService</servlet-name>  
        <url-pattern>/service/sayHi</url-pattern>  
    </servlet-mapping>
    
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

最后打包成war包,发布到tomcat上面,使用第二种发布方式,需要引入jar包:
在这里插入图片描述

注意:
  • 项目需要使用UTF-U编码(至少 sun-jsxws.xml 必须是UTF-8格式的);
  • 对于MyEclipse的内置Tomcat,可能会出现不需要手动添加上述jar包,但独立部署时需 要添加,因为它们使用的class-path不一样;
  • 多个不同路径的接口也要使用同一个WSServlet;
  • 最好加上@SOAPBinding(style=SOAPBinding.Style.RPC)注解

部署好以后,就可以输入网址:http://localhost:8080/testjws/service/sayHi?wsdl ,如果能看到东西,说明部署成功了;
其中 8080是tomcat端口号,testjws是项目名,service/sayHi是配置文件中的url-pattern

对应两种不同的发布方式,获取客户端真实IP的方法

想要获取到真实的IP,必须去获取HttpServletRequest对象

1)对于第一种发布方式,获取客户端ip方法(当存在多重代理时,无法获取真实IP):

@Resource
	private WebServiceContext webServiceContext;
MessageContext mc = webServiceContext.getMessageContext();
//第一种发布方式,只能获取的HttpExchange对象,因为获取HttpServletRequest为NULL
HttpExchange exchange = (HttpExchange)mc.get(JAXWSProperties.HTTP_EXCHANGE);
InetSocketAddress isa = exchange.getRemoteAddress();
ip = isa.getAddress().getHostAddress(); //如果有多重代理,则获取到的IP并非真实IP

2)对于第二种发布方式,获取IP的方法(可以获取真实IP):

@Resource
	private WebServiceContext webServiceContext;
MessageContext mc = webServiceContext.getMessageContext();
//第二种发布方式,是获取HttpServletRequest对象
HttpServletRequest request= (HttpServletRequest)(mc.get(MessageContext.SERVLET_REQUEST));
String ip = IPUtil.getIpAddr(request);

从request中获取真实IP的方法getIpAddr 的实现:

public static String getIpAddr(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
			// 多次反向代理后会有多个ip值,第一个ip才是真实ip
			if (ip.indexOf(",") != -1) {
				ip = ip.split(",")[0];
			}
		}
		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("HTTP_CLIENT_IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		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;
	}
中文乱码通常是由于字符编码不一致导致的。解决方法如下: 1. 在客户端中设置字符编码为UTF-8(或与服务端相同的编码),例如: ```java String encoding = "UTF-8"; BindingProvider provider = (BindingProvider) port; Map<String, Object> requestContext = provider.getRequestContext(); requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpoint); requestContext.put(BindingProvider.USERNAME_PROPERTY, username); requestContext.put(BindingProvider.PASSWORD_PROPERTY, password); requestContext.put(BindingProvider.SESSION_MAINTAIN_PROPERTY, true); requestContext.put(MessageContext.HTTP_REQUEST_HEADERS, headers); requestContext.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192); requestContext.put(BindingProviderProperties.CONNECT_TIMEOUT, 3000); requestContext.put(BindingProviderProperties.REQUEST_TIMEOUT, 3000); requestContext.put(JAXWSProperties.HTTP_RESPONSE_TIMEOUT, 3000); requestContext.put(JAXWSProperties.HTTP_CLIENT_ALLOW_CHUNKING, true); requestContext.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192); requestContext.put(JAXWSProperties.CONNECT_TIMEOUT, 3000); requestContext.put(JAXWSProperties.REQUEST_TIMEOUT, 3000); requestContext.put(JAXWSProperties.HTTP_RESPONSE_TIMEOUT, 3000); requestContext.put(JAXWSProperties.HTTP_CLIENT_ALLOW_CHUNKING, true); requestContext.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192); requestContext.put(BindingProviderProperties.CONNECT_TIMEOUT, 3000); requestContext.put(BindingProviderProperties.REQUEST_TIMEOUT, 3000); requestContext.put(JAXWSProperties.HTTP_RESPONSE_TIMEOUT, 3000); requestContext.put(JAXWSProperties.HTTP_CLIENT_ALLOW_CHUNKING, true); requestContext.put(JAXWSProperties.HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192); //设置字符编码 requestContext.put(BindingProviderProperties.ENCODING, encoding); ``` 2. 在服务端中设置字符编码为UTF-8(或与客户端相同的编码),例如: ```xml <?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://localhost:8080/HelloWorld" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://localhost:8080/HelloWorld"> <types> <xsd:schema> <xsd:import namespace="http://localhost:8080/HelloWorld" schemaLocation="http://localhost:8080/HelloWorld?xsd=1"/> </xsd:schema> </types> <message name="sayHello"> <part name="name" type="xsd:string"/> </message> <message name="sayHelloResponse"> <part name="return" type="xsd:string"/> </message> <portType name="HelloWorld"> <operation name="sayHello"> <input message="tns:sayHello"/> <output message="tns:sayHelloResponse"/> </operation> </portType> <binding name="HelloWorldSoapBinding" type="tns:HelloWorld"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="sayHello"> <soap:operation soapAction=""/> <input> <soap:body use="literal"/> </input> <output> <soap:body use="literal"/> </output> </operation> </binding> <service name="HelloWorldService"> <port name="HelloWorldPort" binding="tns:HelloWorldSoapBinding"> <soap:address location="http://localhost:8080/HelloWorld"/> </port> </service> </definitions> ``` 在这个例子中,我们在WSDL文件头部设置了编码为UTF-8,并在SOAP消息的body元素中使用了use="literal"来指定使用XML文本格式。这样可以确保服务端和客户端使用相同的字符编码,避免中文乱码问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值