这里是webservice的code example,在example的基础上,做了自己的一些更改尝试和总结,目的是加深个人理解。
Example 1(rpc)
step1. server端webservice接口(sei->service endpoint interface)和实现类
package com.caiyun.webservice1.server;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import javax.xml.ws.WebServiceClient;
//SEI
@WebService
//@WebServiceClient, 用来注解在客户端生成的代码上,唯一标识wsdl中的wsdl:service
@SOAPBinding(style = Style.RPC)
public interface HelloWorld {
//@WebMethod
String getHelloWorldAsString(String name);
}
package com.caiyun.webservice1.server;
import javax.jws.WebService;
import javax.xml.ws.WebServiceProvider;
@WebService(endpointInterface = "com.caiyun.webservice1.server.HelloWorld")
//@WebServiceProvider
public class HelloImpl implements HelloWorld {
public HelloImpl() {
// TODO Auto-generated constructor stub
}
public String getHelloWorldAsString(String name) {
// TODO Auto-generated method stub
return "hello caiyun welcome ~~";
}
}
实现类中如果定义了endpointinterface的值,则会找此接口,找不到会报错,且其必需有@webservice注解。
没有定义endpointiterface的值,应该会默认找其实现类,soap style取默认值,默认为document
@WebService的属性皆可ignore,会取默认值。servicename是service的name,默认是实现类名+Service;portName是port的name,有name值则默认是name+port,
targetNameSpace默认是包名反过来;portname默认是实现类名+port
webservice的endpoint的实现类可以有多个,但是必需独立发布,
Step2 service发布
package com.caiyun.webservice1;
import javax.xml.ws.Endpoint;
import com.caiyun.webservice1.server.HelloImpl;
import com.caiyun.webservice1.server.HelloWorld2Impl;
//import com.caiyun.webservice1.server.HelloWorldImpl;
public class HelloWorldPublisher
{
public static void main( String[] args )
{
//arg2必需是有@webservice或者@webserviceprovider(则必需实现provider接口)注解,会根据new的实例类提供的信息创建wsdl包含信息。
Endpoint.publish("http://localhost:8888/ws/nihao", new HelloImpl());
Endpoint.publish("http://localhost:8888/ws/a", new HelloWorld2Impl());
}
}
Step3 访问测试
浏览器访问http://localhost:8888/ws/nihao?wsdl,可查看到wsdl 文件内容
Step4 Client端实现
package com.caiyun.webserviceClient;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ServiceConfigurationError;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import com.caiyun.webservice1.server.HelloWorld;
public class WebServiceClient
{
public static void main( String[] args )
{
QName qName = new QName("http://server.webservice1.caiyun.com/", "HelloImplService");
try {
URL url = new URL("http://localhost:9999/ws/nihao?wsdl");
//客户端需要一个service对象来操作webservice,类似于一个factory,提供操作webservice的一些实例对象
Service service = Service.create(url, qName);
HelloWorld helloWorld = service.getPort(HelloWorld.class);//返回一个代理,jax-ws运行时负责选择一个协议binding和port去配置一个代理
System.out.println(helloWorld.getHelloWorldAsString("nihaozhangdan"));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
其中QName 是xml中定义的,qualified Name,限定名,由namespace、前缀、:组成,实际代表xml中的元素。在这里初始化,需要传入wsdl中的targetNamespace,和name
以上HelloWorld类,和server端sei一样,如下
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import javax.xml.ws.WebServiceClient;
//SEI
@WebService
//@SOAPBinding(style = Style.RPC)
public interface HelloWorld {
//@WebMethod
String getHelloWorldAsString(String name);
}
Example2 wsimport生成客户端代码
以上HelloWorld类需要手动添加,其实我们可以利用生成工具生成。生成工具有很多种,我所用到的有JDK自带的wsimport和maven插件codegen。codegen一般用来项目集成,用在现在流行的springboot当中比较合适和方便。
这里先介绍wsimport。
Step 1
在任意目录下命令行执行:
wsimport -d /Users/caiyun/Documents/caiyun/ -keep http://localhost:9999/ws/nihao?wsdl
注意,java home路径要配好,jdk的bin下有自带的wsimport.
以上命令-d后接生成code后保存的path,生成完后,将code复制到项目目录下。
生成过程自我理解
wsimport根据wsdl生成客户端code时,一个service会生成2个文件(4个,2class,2java,即一个webServiceClient和sei代理类),
根据service创建webserviceclient(关联wsdl中的serviceName,targetnamepace,wsdlLocation),此client继承了service类,会维护一个serviceDelegate。servicedelegate可以获取sei的代理,即webendpoint。
根据service下的port创建client下的webendpoint,webendpoint返回portbinding下的type即sei,operation创建webmethod,message创建method的参数
Step 2
Client端service调用
public static void main(String[] args) {
HelloImplService service = new HelloImplService();//client
HelloWorld helloWorld = service.getPort(HelloWorld.class);//获取代理endpoint
System.out.println(helloWorld.getHelloWorldAsString("123"));
}
Example 3 (document)
Step 1
server端的更改:@SOAPBinding(style = Style.DOCUMENT, use=Use.LITERAL)
@WebService
@SOAPBinding(style = Style.DOCUMENT, use=Use.LITERAL)
public interface HelloWorld {
@WebMethod
String getHelloWorldAsString(String name);
}
Step 2
wsimport 工具生成webservice client code
生成了6个java文件
作为WebEndpoint的HelloWorld.java 有如下不同实现
增加了对request和response的xml元素和java bean的map和封装
Step 4 client 端调用
同Example 2
Soap 消息在Eclipse中的跟踪->TCP/IP Monitor
Step 1 找到TCP/IP Monitor,并设置启动
1.host name:指定要拦截监听的地址,如上边的例子,localhost:8888
2.设置monitor的端口。此时需要将request请求的地址改为localhost:9999
request会到达monitor服务器,然后monitor将request发到localhost:8888.
response回来也会先到达monitor,然后到达真正的client。