论坛首页 Java企业应用论坛

[翻译]CXF用户指南:一个简单的JAX-WS服务

浏览 14705 次
精华帖 (1) :: 良好帖 (0) :: 新手帖 (2) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-08-23   最后修改:2010-12-05
SOA
原文地址:http://cxf.apache.org/docs/a-simple-jax-ws-service.html

这个例子将通过编写JAX-WS来引导你开发第一个服务

  1. 设置构建
  2. 编写服务
  3. 发布服务
  4. 访问服务
同样在CXF发布包中的也可以找到hello_world_code_first示例,注意:这个示例只有在CXF 2.0.1+的版本中!

设置构建

如果你使用Maven来构建你的工程,查看这个页面
否则,打开你最喜爱的IDE,然后创建一个新的工程,我们首先要做的是将CXF依赖的包添加到工程里,你可以在CXF的发布包的ib目录下找到这些依赖包(提示:如果发布包的版本改变,这些jar包上的版本数字可能有所不同)
引用
commons-logging-1.1.1.jar
geronimo-activation_1.1_spec-1.0.2.jar (or Sun's Activation jar)
geronimo-annotation_1.0_spec-1.1.1.jar (JSR 250)
geronimo-javamail_1.4_spec-1.6.jar (or Sun's JavaMail jar)
geronimo-servlet_2.5_spec-1.2.jar (or Sun's Servlet jar)
geronimo-ws-metadata_2.0_spec-1.1.2.jar (JSR 181)
geronimo-jaxws_2.1_spec-1.0.jar (or Sun's jaxws-api-2.1.jar)
geronimo-stax-api_1.0_spec-1.0.1.jar (or other stax-api jar)
jaxb-api-2.1.jar
jaxb-impl-2.1.12.jar
jetty-6.1.21.jar
jetty-util-6.1.21.jar
neethi-2.0.4.jar
saaj-api-1.3.jar
saaj-impl-1.3.2.jar
wsdl4j-1.6.2.jar
wstx-asl-3.2.8.jar
XmlSchema-1.4.5.jar
xml-resolver-1.2.jar

Spring依赖包 (非必须- 为了支持XML配置):
引用
aopalliance-1.0.jar
spring-core-2.5.5.jar
spring-beans-2.5.5.jar
spring-context-2.5.5.jar
spring-web-2.5.5.jar

还需要CXF的jar包:
引用
cxf-2.2.3.jar

编写服务

首先,我们将编写服务的接口,这个接口只有一个"sayHello" 的方法,这个方法会对提交他们名字的用户说 "Hello"
@WebService
public interface HelloWorld {

    String sayHi(String text);

    /* 进阶应用,JAX-WS/JAXB不支持自定义类型参数如User
     * 需要编写XmlAdapter类来处理自定义类型
     */
    String sayHiToUser(User user);

    /* Map传递
     * JAXB同样也不支持Maps.处理Lists很轻松,但是不直接支持Maps
     * 同样也需要使用XmlAdapter来映射maps到JAXB能处理的beans
     */
    @XmlJavaTypeAdapter(IntegerUserMapAdapter.class)
    Map<Integer, User> getUsers();
}
为了确认参数在xml文件中名称正确,你需要使用:
@WebService
public interface HelloWorld {
    String sayHi(@WebParam(name="text") String text);
}
因为java接口在.class文件中不存储参数名称,所以@WebParam注解是必须的,因此如果你不使用这个注解,参数将被命名为arg0

我们的实现将像这样:
package demo.hw.server;

import java.util.LinkedHashMap;
import java.util.Map;

import javax.jws.WebService;

@WebService(endpointInterface = "demo.hw.server.HelloWorld",
            serviceName = "HelloWorld")
public class HelloWorldImpl implements HelloWorld {
    Map<Integer, User> users = new LinkedHashMap<Integer, User>();

    public String sayHi(String text) {
        System.out.println("sayHi called");
        return "Hello " + text;
    }

    public String sayHiToUser(User user) {
        System.out.println("sayHiToUser called");
        users.put(users.size() + 1, user);
        return "Hello "  + user.getName();
    }

    public Map<Integer, User> getUsers() {
        System.out.println("getUsers called");
        return users;
    }

}
在实现类上的@WebService注解使CXF知道使用那个接口来创建WSDL,我们示例中是HelloWorld接口

发布服务
System.out.println("Starting Server");
HelloWorldImpl implementor = new HelloWorldImpl();
String address = "http://localhost:9000/helloWorld";
Endpoint.publish(address, implementor);
完整的代码在http://svn.apache.org/repos/asf/cxf/trunk/distribution/src/main/release/samples/java_first_jaxws/src/demo/hw/server/Server.java

或者你可以使用下列代码,通过如下代码,你可以更多控制行为,例如你可以添加日志拦截器
HelloWorldImpl implementor = new HelloWorldImpl();
JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
svrFactory.setServiceClass(HelloWorld.class);
svrFactory.setAddress("http://localhost:9000/helloWorld");
svrFactory.setServiceBean(implementor);
svrFactory.getInInterceptors().add(new LoggingInInterceptor());
svrFactory.getOutInterceptors().add(new LoggingOutInterceptor());
svrFactory.create();
你可以忽略设置ServiceClass,但是最好设置,这样可以使服务端和客户端都从同样的接口创建而来,如果你使用实现类来作为替代可能会出现问题

浏览器里输入http://localhost:9000/helloWorld?wsdl显示出这个服务的wsdl

访问服务

同样客户端代码在http://svn.apache.org/repos/asf/cxf/trunk/distribution/src/main/release/samples/java_first_jaxws/src/demo/hw/client/Client.java

对于客户端,同样也有替代方法给予你更多的伸缩性,当然如上一个示例的日志拦截器也是可选择的,但是对于初学者帮助很大:
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.getInInterceptors().add(new LoggingInInterceptor());
factory.getOutInterceptors().add(new LoggingOutInterceptor());
factory.setServiceClass(HelloWorld.class);
factory.setAddress("http://localhost:9000/helloWorld");
HelloWorld client = (HelloWorld) factory.create();

String reply = client.sayHi("HI");
System.out.println("Server said: " + reply);
System.exit(0); 
   发表时间:2010-09-23   最后修改:2010-09-23

FuseSource 上有一些介绍如何使用 Apache CXF的文档, 有兴趣的朋友可以访问下面的链接。

http://fusesource.com/products/enterprise-cxf/#documentation

 

0 请登录后投票
   发表时间:2010-09-24  
刚后有个问题求教一下啊:
我前几天也在倒腾CXF, 但有一个问题一直没有解决:我实验了以后怎么客户端的调用接口文件必须和服务端发布服务用的接口文件在同一个包路径下面啊。就是说他们的包路径在发布服务的工程里面和消费服务的工程里面必须要相同的包路径上。我是用的CXF和Spring集成的方法来弄的。不晓得哪里没搞对!望指教啊
0 请登录后投票
   发表时间:2010-09-25  
这边做项目通常都是将编写的服务接口,示例中的HelloWorld接口,打一个jar,发给客户,所以肯定是同一包名的接口,这样操作有点像EJB,因为这边都是不同厂商给某运营商服务,厂商之间互联,用这种方式图个方便,还有一种方式WSDL to Java,手里只有WDSL,查看下http://cxf.apache.org/docs/wsdl-to-java.html
0 请登录后投票
   发表时间:2010-09-25   最后修改:2010-09-25
dandan_5956 写道
这边做项目通常都是将编写的服务接口,示例中的HelloWorld接口,打一个jar,发给客户,所以肯定是同一包名的接口,这样操作有点像EJB,因为这边都是不同厂商给某运营商服务,厂商之间互联,用这种方式图个方便,还有一种方式WSDL to Java,手里只有WDSL,查看下http://cxf.apache.org/docs/wsdl-to-java.html

豁然开朗啊!多谢楼主了!纠结了偶一个中秋节,原来服务端和客户端的接口就得在同一个包结构下。打个接口的jar包丢给客户端的确是个好办法又不影响客户端工程的包结构,我怎么没想出来。。哎。。。
刚试用了一下Wsdl2Java也很好用~~~~
0 请登录后投票
   发表时间:2010-09-25  
但是有个问题 用WSDL2java工具生成的接口文件,需要我指定一个包路径啊。这个包路径不能根据wsdl文件自动生成?
0 请登录后投票
   发表时间:2010-09-25  
按照楼主的样子写了个简单的例子

package test.demon;

import javax.jws.WebService;

@WebService(endpointInterface = "com.sitech.demon.HelloWorld")
public class HelloWorldImpl implements HelloWorld {

public String sayHello(String tipMsg) {
System.out.println("In Message:" + tipMsg);
return "out message";
}

}


启动服务报错,楼主有碰到过吗?
[JAM] Warning: failed to resolve class test.demon.HelloWorldImpl
<2010-9-25 下午11时00分22秒 CST> <Error> <HTTP> <BEA-101216> <Servlet: "test.demon.HelloWorldImpl" failed to preload on startup in Web application: "WebRoot".
class: test.demon.jaxws.SayHello could not be found
at com.sun.xml.ws.model.RuntimeModeler.getClass(RuntimeModeler.java:272)
at com.sun.xml.ws.model.RuntimeModeler.processDocWrappedMethod(RuntimeModeler.java:566)
at com.sun.xml.ws.model.RuntimeModeler.processMethod(RuntimeModeler.java:513)
at com.sun.xml.ws.model.RuntimeModeler.processClass(RuntimeModeler.java:358)
at com.sun.xml.ws.model.RuntimeModeler.buildRuntimeModel(RuntimeModeler.java:245)
Truncated. see log file for complete stacktrace
0 请登录后投票
   发表时间:2010-09-25  
@WebService(endpointInterface = "com.sitech.demon.HelloWorld")
改成
@WebService
0 请登录后投票
   发表时间:2010-09-26  
angelbear220 写道
按照楼主的样子写了个简单的例子

package test.demon;

import javax.jws.WebService;

@WebService(endpointInterface = "com.sitech.demon.HelloWorld")
public class HelloWorldImpl implements HelloWorld {

public String sayHello(String tipMsg) {
System.out.println("In Message:" + tipMsg);
return "out message";
}

}


启动服务报错,楼主有碰到过吗?
[JAM] Warning: failed to resolve class test.demon.HelloWorldImpl
<2010-9-25 下午11时00分22秒 CST> <Error> <HTTP> <BEA-101216> <Servlet: "test.demon.HelloWorldImpl" failed to preload on startup in Web application: "WebRoot".
class: test.demon.jaxws.SayHello could not be found
at com.sun.xml.ws.model.RuntimeModeler.getClass(RuntimeModeler.java:272)
at com.sun.xml.ws.model.RuntimeModeler.processDocWrappedMethod(RuntimeModeler.java:566)
at com.sun.xml.ws.model.RuntimeModeler.processMethod(RuntimeModeler.java:513)
at com.sun.xml.ws.model.RuntimeModeler.processClass(RuntimeModeler.java:358)
at com.sun.xml.ws.model.RuntimeModeler.buildRuntimeModel(RuntimeModeler.java:245)
Truncated. see log file for complete stacktrace

从报错的信息看出是HelloWorldImpl没有正确加载,你是采用Web工程来编写,所给信息不是很全,我也不能断定是什么问题,示例中是Java工程,通过http://svn.apache.org/repos/asf/cxf/trunk/distribution/src/main/release/samples/java_first_jaxws/src/demo/hw/server/Server.java中Server类的调用Jetty来发布的服务,我试过没有什么问题。
0 请登录后投票
   发表时间:2010-09-26  
eredlab 写道
但是有个问题 用WSDL2java工具生成的接口文件,需要我指定一个包路径啊。这个包路径不能根据wsdl文件自动生成?

WSDL2Java的方式,我没有具体尝试过,有一点是WSDL包含的是关于Web Service服务的描述,自然里面应该不会包含关于包名的信息,所以也应该不能自动生成,具体还是只有看CXF文档如何描述的。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics