服务端
首先是SEI
,即服务端接口类HelloService.Java
package com.xuanyuv.service;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
@WebService(targetNamespace="https://www.xuanyuv.com/")
public interface HelloService {
@WebResult(name="sayHelloResult")
public String sayHello(@WebParam(name="name")String name);
}
下面是SIB
,即服务端接口实现类HelloServiceImpl.java
package com.xuanyuv.service;
import javax.annotation.Resource;
import javax.jws.WebService;
import javax.servlet.http.HttpServletRequest;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import org.springframework.stereotype.Service;
import com.xuanyuv.dao.HelloDaoJDBC;
/**
* JAX-WS与Spring集成时获取HttpServletAPI
* 1、SIB中直接使用@Resource注入javax.xml.ws.WebServiceContext
* 2、使用wsc.getMessageContext().get(SOAPMessageContext.SERVLET_REQUEST)获取HttpServletRequest
* 但前提是SIB已被Spring所管理...本例中的明显特征是SIB上使用了@Service注解
* Created by 玄玉<https://www.xuanyuv.com/> on 2013/05/27 18:10.
*/
@WebService(serviceName="myHelloService",
targetNamespace="https://www.xuanyuv.com/",
endpointInterface="com.xuanyuv.service.HelloService")
@Service
public class HelloServiceImpl implements HelloService {
@Resource
private HelloDaoJDBC helloDao;
@Resource
private WebServiceContext wsc;
@Override
public String sayHello(String name) {
MessageContext ctx = wsc.getMessageContext();
HttpServletRequest request = (HttpServletRequest)ctx.get(SOAPMessageContext.SERVLET_REQUEST);
System.out.println("----------------------------------------------------------------------");
System.out.println("ServletContextName=" + request.getSession().getServletContext().getServletContextName());
System.out.println("ContextPath=" + request.getSession().getServletContext().getContextPath());
System.out.println("RealPath=" + request.getSession().getServletContext().getRealPath("/"));
System.out.println("ServerInfo=" + request.getSession().getServletContext().getServerInfo());
System.out.println("----------------------------------------------------------------------");
return helloDao.sayHello(name);
}
}
下面是服务端模拟的一个DAO实现类HelloDaoJDBC.java
package com.xuanyuv.dao;
import org.springframework.stereotype.Repository;
@Repository("helloDao")
public class HelloDaoJDBC {
public String sayHello(String name) {
System.out.println("Receive the name=[" + name + "]");
if(null==name){
return "Hello,World";
}else{
return "Hello," + name;
}
}
}
下面是服务端自定义的Handler类LicenseHandler.java
package com.xuanyuv.handler;
import java.util.Iterator;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
public class LicenseHandler implements SOAPHandler<SOAPMessageContext> {
@Override
public Set<QName> getHeaders() {
return null;
}
@Override
public void close(MessageContext context) {}
@Override
public boolean handleFault(SOAPMessageContext context) {
System.out.println("Server.handleFault() is invoked......");
return false;
}
@Override
@SuppressWarnings("unchecked")
public boolean handleMessage(SOAPMessageContext context) {
System.out.println("Server.handleMessage() is invoked......");
//只有Handler被纳入Spring管理后,这里获取到的HttpServletRequest才不是null
HttpServletRequest request = (HttpServletRequest)context.get(SOAPMessageContext.SERVLET_REQUEST);
System.out.println("RealPath=" + request.getSession().getServletContext().getRealPath("/"));
//从服务端角度看:inbound表示接收客户端消息,outbound表示响应消息给客户端..从客户端角度看则正好相反
Boolean isOutBound = (Boolean)context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if(isOutBound){
return true;
}
SOAPMessage message = context.getMessage();
SOAPHeader header = null;
SOAPBody body = null;
try {
SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
header = envelope.getHeader();
body = envelope.getBody();
} catch (SOAPException e) {
e.printStackTrace();
}
//获取Body中的part name
String partName = body.getChildNodes().item(0).getLocalName();
//只对服务端开放的login()方法进行验证,否则它会对服务端开放的所有方法进行验证
if(!"sayHello".equals(partName)){
return true;
}
if(null==header){
System.out.println("未找到头信息......");
return true;
}
Iterator<SOAPHeaderElement> iterator = header.extractAllHeaderElements();
if(!iterator.hasNext()){
System.out.println("头信息不能为空......");
return true;
}
System.out.println("协议有效......");
while(iterator.hasNext()){
System.out.println(iterator.next().getTextContent());
}
return true;
}
}
下面是Spring的配置文件applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:core="http://jax-ws.dev.java.net/spring/core" xmlns:servlet="http://jax-ws.dev.java.net/spring/servlet" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://jax-ws.dev.java.net/spring/core http://jax-ws.dev.java.net/spring/core.xsd http://jax-ws.dev.java.net/spring/servlet http://jax-ws.dev.java.net/spring/servlet.xsd">
<context:component-scan base-package="com.xuanyuv"/>
<!--
JAX-WS与Spring集成
有两种比较好的方式:一个是Spring提供的SimpleJaxWsServiceExporter,一个是jaxws-spring提供的WSSpringServlet
这两种方式的不同之处仅在于配置文件的不同,而SEI和SIB都是一样的
补充一下:之所以让JAX-WS与Spring集成,主要是让SIB纳入Spring的管理,这样方便我们往SIB注入东西,比如DAO等等
-->
<!-- ******************************************************************************************* -->
<!-- 下面演示Spring提供的SimpleJaxWsServiceExporter的写法 -->
<!-- ******************************************************************************************* -->
<!--
SimpleJaxWsServiceExporter会自动搜索包中含有javax.jws.WebService注解的类,并将之发布为WebService
这种方式可以直接向SIB中注入对象,因为这个WebService已被Spring所管理,详见本例中的HelloServiceImpl.java
value用于指明发布地址,不强制要求与Web应用地址相同,访问时的地址是'value'加上@WebService(serviceName='')
value="http://127.0.0.1:8088/mytest",则服务地址为http://127.0.0.1:8088/mytestmyHelloService?wsdl
value="http://127.0.0.1:8088/mytest",则服务地址为http://127.0.0.1:8088/mytest/myHelloService?wsdl
这种集成方式所发布的WebService是一种独立的WebService
-->
<!--
<bean class="org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter">
<property name="baseAddress" value="http://127.0.0.1:8088/mytest/"/>
</bean>
-->
<!-- ******************************************************************************************* -->
<!-- 下面演示jaxws-spring提供的WSSpringServlet的写法 -->
<!-- ******************************************************************************************* -->
<!--
jaxws-spring的WSSpringServlet开发步骤如下
1)导入jaxws-spring-1.8.jar,xbean-spring-3.13.jar,jaxws-ri-2.2.7工具包,三者下载地址如下
http://repo1.maven.org/maven2/org/jvnet/jax-ws-commons/spring/jaxws-spring/1.8/
http://repo1.maven.org/maven2/org/apache/xbean/xbean-spring/3.13/
https://jax-ws.java.net(我下载到的最新版为JAXWS2.2.7-20120813.zip)
2)在Spring配置文件中增加jaxws-spring的两个xsd
注意加入的是http://jax-ws.dev.java.net/spring/core.xsd,不是spring-jax-ws-core.xsd,否则会报错
3)在MyEclipse中为xml文件增加jaxws-spring的两个schema,以便于applicationContext.xml中编写jaxws-spring标签
Preferences-MyEclipse Enterprise Workbench-Files and Editors-XML-XML Catalog-User Specified Entries
Location:选择File System后选中本地硬盘的spring-jax-ws-core.xsd(可直接从jaxws-spring-1.8.jar中解压出来)
Key type:选为System ID
Key:输入http://jax-ws.dev.java.net/spring/core.xsd
4)编写WSSpringServlet在applicationContext.xml中的配置
5)编写web.xml
-->
<!-- 这里url的值一定要与web.xml中为WSSpringServlet配置的<url-pattern>值相同 -->
<!-- Web应用启动后,公布服务的访问地址就是http://127.0.0.1:8088/webPath/myService?wsdl -->
<servlet:binding url="/myService">
<servlet:service>
<!-- bean属性表示WebService的注入对象,注意其值要在开头加井号,后跟Spring管理的SIB的Bean名称 -->
<core:service bean="#helloServiceImpl">
<!-- 此时就不需要在SIB中指定@HandlerChain(file="myHandlerChain.xml") -->
<!-- 也不用编写myHandlerChain.xml了 -->
<core:handlers>
<bean class="com.xuanyuv.handler.LicenseHandler"/>
</core:handlers>
<!-- 主动声明wsdl文件import或include的外部文件,否则其发布的wsdl中是不会正确引入xsd的 -->
<!--
<core:metadata>
<value>/WEB-INF/wsdl/myhello.xsd</value>
</core:metadata>
-->
</core:service>
</servlet:service>
</servlet:binding>
</beans>
下面这个是便于日志打印的log4j.properties
# https://github.com/xuanyuv/seed/blob/master/seed-comm/src/main/java/com/xuanyuv/seed/comm/util/LogUtil.java
log4j.rootLogger=DEBUG,CONSOLE
#通常用于框架日志,如mina,spring等
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=DEBUG
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%d{yyyyMMdd HH:mm:ss}][%t][%C{1}]%m%n
最后是服务端的web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 针对jaxws-spring的配置 -->
<servlet>
<servlet-name>jaxws-servlet</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSSpringServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>jaxws-servlet</servlet-name>
<url-pattern>/myService</url-pattern>
</servlet-mapping>
</web-app>
至此服务端发布完毕
客户端
首先是客户端自定义的HeaderHandler.java
package com.xuanyuv.handler;
import java.io.IOException;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
public class HeaderHandler implements SOAPHandler<SOAPMessageContext> {
@Override
public Set<QName> getHeaders() {
return null;
}
@Override
public void close(MessageContext context) {}
@Override
public boolean handleFault(SOAPMessageContext context) {
System.out.println("\nClient.handleFault() is invoked.....");
return false;
}
@Override
public boolean handleMessage(SOAPMessageContext context) {
System.out.println("\nClient.handleMessage() is invoked.....");
Boolean isOutBound = (Boolean)context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if(isOutBound){
SOAPMessage message = context.getMessage();
try {
SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
SOAPHeader header = envelope.getHeader();
String partName = envelope.getBody().getFirstChild().getLocalName();
if("sayHello".equals(partName)){
if(null == header){
header = envelope.addHeader();
}
QName qname = new QName("https://www.xuanyuv.com/", "licenseInfo", "ns");
header.addHeaderElement(qname).setValue("Xuanyu");
message.writeTo(System.out);
}
} catch (SOAPException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}
}
接下来是客户端与Spring集成用到的HeaderHandlerResolver.java
package com.xuanyuv.handler;
import java.util.ArrayList;
import java.util.List;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.HandlerResolver;
import javax.xml.ws.handler.PortInfo;
import org.springframework.stereotype.Component;
@Component
public class HeaderHandlerResolver implements HandlerResolver {
@SuppressWarnings("unchecked")
@Override
public List<Handler> getHandlerChain(PortInfo portInfo) {
List<Handler> handlers = new ArrayList<Handler>();
handlers.add(new HeaderHandler());
return handlers;
}
}
下面是客户端模拟的一个Service实现类ClientService.java
package com.xuanyuv.service;
import javax.annotation.Resource;
import net.csdn.blog.xuanyuv.HelloService;
import org.springframework.stereotype.Service;
@Service
public class ClientService {
@Resource
private HelloService myServerWebService;
public String getServerResponse(String name){
return myServerWebService.sayHello(name);
}
}
下面是客户端的Spring配置文件applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="com.xuanyuv"/>
<!-- 这样就可以在客户端把一个WebService注入到其它的bean中了 -->
<bean id="myServerWebService" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<!--
记得首先还是要使用wsimport生成客户端代码,然后将接口类全路径写在serviceInterface的值里
关于wsimport的使用,可参考https://www.xuanyuv.com/blog/20130319/jaxws-and-wsimport-demo.html
wsimport -d D:/Download/ -keep -verbose http://127.0.0.1:8088/jaxws-spring/myService?wsdl
-->
<property name="serviceInterface" value="net.csdn.blog.xuanyuv.HelloService"/>
<property name="wsdlDocumentUrl" value="http://127.0.0.1:8088/jaxws-spring/myService?wsdl"/>
<property name="namespaceUri" value="https://www.xuanyuv.com/"/>
<property name="serviceName" value="myHelloService"/>
<property name="portName" value="HelloServiceImplPort"/>
<!-- 使用handlerResolver属性来启用Handler,其属性值应为javax.xml.ws.handler.HandlerResolver类型 -->
<!-- 所以自定义了一个实现HandlerResolver的类,详见com.xuanyuv.handler.HeaderHandlerResolver.java -->
<property name="handlerResolver" ref="headerHandlerResolver"/>
</bean>
</beans>
最后是客户端调用服务端的模拟入口ClientApp.java
它是通过wsimport生成的,关于其用法,可参考https://www.xuanyuv.com/blog/20130319/jaxws-and-wsimport-demo.html
package com.xuanyuv.client;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.xuanyuv.service.ClientService;
public class ClientApp {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ClientService cs = (ClientService)ctx.getBean("clientService");
System.out.println(cs.getServerResponse("玄玉"));
}
}
控制台输出
//客户端
Client.handleMessage() is invoked.....
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Header><ns:licenseInfo xmlns:ns="https://www.xuanyuv.com/">Xuanyuv</ns:licenseInfo></S:Header><S:Body><ns2:sayHello xmlns:ns2="https://www.xuanyuv.com/"><name>玄玉</name></ns2:sayHello></S:Body></S:Envelope>
Client.handleMessage() is invoked.....
Hello,玄玉
//服务端
Server.handleMessage() is invoked......
RealPath=D:\Develop\apache-tomcat-6.0.36\webapps\jaxws-spring\
协议有效......
Xuanyu
----------------------------------------------------------------------
ServletContextName=null
ContextPath=/jaxws-spring
RealPath=D:\Develop\apache-tomcat-6.0.36\webapps\jaxws-spring\
ServerInfo=Apache Tomcat/6.0.36
----------------------------------------------------------------------
Receive the name=[玄玉]
Server.handleMessage() is invoked......
RealPath=D:\Develop\apache-tomcat-6.0.36\webapps\jaxws-spring\