???service.addPort(PORT_NAME,0)">???????
上面这种通过Service来获取WebService的方法是不适用前面介绍的简单WebService实现的,即不适用获取通过ServerFactoryBean发布的WebService。
?
4???????java2ws工具的使用
???????Cxf为我们提供了一个java2ws工具。通过该工具我们可以根据SEI(Service Endpoint Implementation的缩写)类及其相关的类来生成WebService的服务端、客户端和wsdl文件等。SEI需要是使用了@WebService标注的Service接口或类。
4.1?????命令行使用java2ws
???????在Cxf根目录下的bin目录下有一个java2ws工具,我们可以在命令行下使用该指令生成相应代码。Java2ws指令后面可以接很多参数,主要有:
参数名 |
作用 |
-?|-h|-help |
这三个参数都可输出java2ws指令的帮助信息 |
-wsdl |
生成wsdl文件 |
-o fileName |
指定生成的wsdl文件的名称 |
-d resourceDir |
指定资源文件存放的目录,生成的wsdl文件也会放在该目录下 |
-server |
指定生成服务端代码 |
-client |
指定生成客户端代码 |
-wrapperbean |
指定生成wrapper和fault bean |
-cp classpath |
指定java2ws搜寻SEI和相关类型类的路径 |
-t targetNameSpace |
指定targetNameSpace |
-servicename serviceName |
指定serviceName |
-verbose |
在生成代码的时候显示注释信息 |
-quiet |
在生成代码的时候不显示注释信息 |
-s sourceDir |
指定生成的java代码存放的目录 |
-classdir classdir |
指定生成的java代码编译后的class类存放的目录 |
className |
指定SEI类的名称 |
???????在使用java2ws指令时className是必须给定的,其他的参数都可选。java2ws将会到classpath路径下或使用-cp参数指定的classpath路径下寻找SEI类及其相关类型。
???????示例:
???????java2ws –server com.tiantian.cxftest.sample.jaxws.HelloWorld(生成服务端代码)
???????java2ws –wsdl –cp . com.tiantian.cxftest.sample.jaxws.HelloWorld(在当前目录下寻找HelloWorld类生成wsdl文件)
4.2?????Maven使用java2ws
???????Cxf为java2ws工具提供了一个Maven的插件,叫cxf-java2ws-plugin。所以当我们的项目是使用Maven的时候我们可以在项目的pom.xml文件中加入Cxf提供的cxf-java2ws-plugin,这样当我们执行Maven的某个操作的时候就会触发java2ws指令生成对应的代码。如:
<plugin>??
???<groupId>org.apache.cxf</groupId>??
???<artifactId>cxf-java2ws-plugin</artifactId>??
???<version>${cxf.version}</version>??
???<executions>??
??????<execution>??
?????????<id>process-classes</id>??
?????????<phase>process-classes</phase>??
?????????<configuration>??
?????????????<className>com.tiantian.cxftest.sample.jaxws.HelloWorld</className>??
?????????????<genWsdl>true</genWsdl>??
?????????????<verbose>true</verbose>??
?????????</configuration>??
?????????<goals>??
?????????????<goal>java2ws</goal>??
?????????</goals>??
??????</execution>??
???</executions>??
</plugin>??
???????对于java2ws指令的参数可以通过configuration元素下的元素来指定。可以配置的参数如下:
参数名 |
作用 |
className |
指定SEI类的名称 |
classpath |
搜选SEI类等相关类的类路径,默认情况下会到当前项目的类路径下寻找 |
outputFile |
生成的wsdl文件存放的位置,默认是${project.build.directory}/generated/wsdl/${className}.wsdl |
genWsdl |
默认为true。是否生成wsdl文件。 |
genServer |
默认false。是否生成Server端代码。 |
genClient |
默认为false。是否生成Client端代码。 |
genWrapperbean |
默认为false。是否生成wrapper bean |
frontend |
表明使用的frontend。支持jaxws和simple,默认是jaxws。 |
databinding |
指定数据绑定。默认frontend为jaxws时用jaxb,simple用aegis |
serviceName |
指定serviceName |
soap12 |
指定生成的wsdl文件包含soap1.2绑定 |
targetNameSpace |
指定用来生成wsdl文件时的target namespace |
verbose |
生成代码的过程中显示注释信息 |
quiet |
在生成代码的时候不显示注释信息 |
attachWsdl |
当为true时,在对当前项目进行Maven的install操作时会把生成的wsdl文件以当前项目的groupId、artifactId和version,以type为wsdl一起安装到Maven的repository中去。默认为true |
address |
指定port的address |
???????使用cxf-java2ws-plugin插件生成的Java代码默认会放在项目的根目录下。
5???????基于Spring的Jax-ws WebService
5.1?????Service定义?
???????Service定义跟之前的定义是一样的。
5.2?????服务端发布Service
???????首先在web.xml文件中定义一个CXFServlet,用于发布和拦截WebService请求。
<!--?Jax-ws实现?-->??
<servlet>??
???<display-name>jaxws-cxf</display-name>??
???<servlet-name>jaxws-cxf</servlet-name>??
???<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>??
???<load-on-startup>1</load-on-startup>??
???<init-param>??
??????<param-name>config-location</param-name>??
??????<param-value>WEB-INF/jaxws-cxf-servlet.xml</param-value>??
???</init-param>??
</servlet>??
??
<servlet-mapping>??
???<servlet-name>jaxws-cxf</servlet-name>??
???<url-pattern>/jaxws/services/*</url-pattern>??
</servlet-mapping>??
???????接下来在我们的WebService配置文件里面定义我们的WebService发布,即CXFServlet指定的jaxws-cxf-servlet.xml文件(默认是cxf-servlet.xml文件)。这里我们定义如下:
<beans?xmlns="http://www.springframework.org/schema/beans"??
???xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"?xmlns:jaxws="http://cxf.apache.org/jaxws"??
???xsi:schemaLocation="??
http://www.springframework.org/schema/beans?http://www.springframework.org/schema/beans/spring-beans.xsd??
http://cxf.apache.org/jaxws?http://cxf.apache.org/schemas/jaxws.xsd">??
???
???<!--?相当于使用Endpoint.publish()进行服务发布?-->??
???<jaxws:endpoint?address="/HelloWorld"?implementorClass="com.tiantian.cxftest.sample.jaxws.HelloWorldImpl"/>??
???
???<!--?相当于使用JaxWsServerFactoryBean进行服务发布?-->??
???<jaxws:server?address="/HelloWorld2"?serviceClass="com.tiantian.cxftest.sample.jaxws.HelloWorldImpl"/>??
?????
???<!--?JaxWsServerFactoryBean使用外部bean作为服务进行发布?-->??
???<jaxws:server?address="/HelloWorld3"?serviceBean="#hw"/>??
???<!--?普通bean对象?-->??
???<bean?id="hw"?class="com.tiantian.cxftest.sample.jaxws.HelloWorldImpl"/>??
?????
???<!--?JaxWsServerFactoryBean使用内部bean作为服务进行发布?-->??
???<jaxws:server?address="/HelloWorld4">??
??????<jaxws:serviceBean>??
?????????<bean?class="com.tiantian.cxftest.sample.jaxws.HelloWorldImpl"/>??
??????</jaxws:serviceBean>??
???</jaxws:server>??
???
</beans>??
5.3?????客户端获取Service
???????客户端可以直接从Spring的bean配置文件中把WebService配置为一个个普通的Spring bean对象进行使用。这主要有两种方式,第一种是使用Jaxws命名空间,第二种是使用JaxWsProxyFactoryBean。
第一种:
???????在定义之前需要往bean配置文件中引入Jax-ws的命名空间。这里我们在classpath下定义一个jaxws-cxf-client.xml文件,其内容如下所示:
<beans?xmlns="http://www.springframework.org/schema/beans"??
???xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"?xmlns:jaxws="http://cxf.apache.org/jaxws"??
???xsi:schemaLocation="??
http://www.springframework.org/schema/beans?http://www.springframework.org/schema/beans/spring-beans.xsd??
http://cxf.apache.org/jaxws?http://cxf.apache.org/schemas/jaxws.xsd">??
???
???<jaxws:client?id="hw"??
??????address="http://localhost:8080/test/jaxws/services/HelloWorld"??
??????serviceClass="com.tiantian.cxftest.sample.jaxws.HelloWorld"?/>??
???
???<jaxws:client?id="hw2"??
??????address="http://localhost:8080/test/jaxws/services/HelloWorld2"??
??????serviceClass="com.tiantian.cxftest.sample.jaxws.HelloWorld"/>??
????????
???<jaxws:client?id="hw3"??
??????address="http://localhost:8080/test/jaxws/services/HelloWorld3"??
??????serviceClass="com.tiantian.cxftest.sample.jaxws.HelloWorld"/>??
????????
???<jaxws:client?id="hw4"??
??????address="http://localhost:8080/test/jaxws/services/HelloWorld4"??
??????serviceClass="com.tiantian.cxftest.sample.jaxws.HelloWorld"/>??
???
</beans>??
??
第二种:
<bean?id="factoryBean"?class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">??
???<property?name="address"?value="http://localhost:8080/test/jaxws/services/HelloWorld"/>??
???<property?name="serviceClass"?value="com.tiantian.cxftest.sample.jaxws.HelloWorld"/>??
</bean>??
??
<bean?id="helloWorld"?factory-bean="factoryBean"?factory-method="create"/>??
? ? ? ?之后我们就可以把这些定义好的WebService当做一个普通的bean对象来使用了,如:
public?class?SpringClient?{??
??
????public?static?void?main(String?args[])?{??
????????ApplicationContext?context?=?new?ClassPathXmlApplicationContext("jaxws-cxf-client.xml");??
????????accessService(context,?"hw");??
????????accessService(context,?"hw2");??
????????accessService(context,?"hw3");??
????????accessService(context,?"hw4");??
????????accessService(context,?"helloWorld");??
????}??
??????
????private?static?void?accessService(ApplicationContext?context,?String?beanName)?{??
????????HelloWorld?hw?=?context.getBean(beanName,?HelloWorld.class);??
????????System.out.println(hw.sayHi("world"));??
????}??
??????
}??
6???????WSDL生成Java代码
???????如果我们已经有了wsdl定义文件的话,我们就可以通过wsdl文件生成对应的Java代码,包括WebService的Service类定义、服务端代码、客户端代码等。这里主要介绍两种WSDL生成Java代码的方式。
6.1?????wsdl2java工具
???????wsdl2java是CXF自带的工具,在CXF根目录下的bin目录下。我们可以在命令行使用这一工具。wsdl2java命令后可以接很多参数,主要有:
参数 |
作用 |
-?|-h|-help |
这三个参数都可以查看wsdl2java指令的帮助信息,可以查看wsdl2java可以带哪些参数 |
-p packageName |
指定生成的java类使用的包名称,如未指定将根据wsdl文件里面的targetNameSpace来决定。 |
-d dir |
生成的Java文件的存放在dir目录 |
-compile |
编译生成的Java文件 |
-classdir dir |
指定编译生成的文件存放在dir目录下 |
-server |
生成WebService的服务端发布代码 |
-client |
生成WebService的客户端访问代码 |
-impl |
生成Service类的实现类代码,即上面的HelloWorldImpl |
-all |
生成所有可以生成的代码 |
wsdlurl |
Wsdl文件的访问路径,可以是本地file,也可以是web上的请求。 |
???????如:wsdl2java –all http://localhost:8080/test/services/HelloWorld?wsdl
???????wsdl2java在生成Service实现类的时候只会生成基本的代码结构,至于里面的操作的具体逻辑还需要我们自己来实现。
6.2?????cxf-codegen-plugin
???????cxf-codegen-plugin是cxf针对于maven的一个插件。当我们的项目是基于Maven的项目时,我们可以在pom.xml文件中引入cxf-codegen-plugin,如:
<plugin>??
???<groupId>org.apache.cxf</groupId>??
???<artifactId>cxf-codegen-plugin</artifactId>??
???<version>2.7.6</version>??
???<executions>??
???????<execution>??
??????????<id>generate-sources</id>??
??????????<phase>generate-sources</phase>??
??????????<goals>??
?????????????<goal>wsdl2java</goal>??
??????????</goals>??
??????????<configuration>??
?????????????<sourceRoot>${project.build.directory}/generated-sources/cxf</sourceRoot>??
?????????????<wsdlOptions>??
????????????????<wsdlOption>??
???????????????????<wsdl>${basedir}/src/main/resources/HelloWorld.wsdl</wsdl>??
????????????????</wsdlOption>??
?????????????</wsdlOptions>??
??????????</configuration>??
???????</execution>??
???</executions>??
</plugin>??
在上面例子中,当我们执行mvn generate-sources时就会运行wsdl2java这个指令。其配置信息是通过configuration元素来指定的。通过sourceRoot可以指定生成的Java代码的存放位置,上面我们指定了生成代码的存放位置为target目录下的generated-sources/cxf目录,该目录也是在没有指定sourceRoot时,cxf-codegen-plugin存放生成的Java代码的默认位置。每个wsdlOption元素对应于一个用来生成代码的WSDL定义。wsdl元素用于指定wsdl文件的存放位置。wsdl2java指令的其他参数可以通过wsdlOption元素下的extraargs元素来指定。如:
<plugin>??
???<groupId>org.apache.cxf</groupId>??
???<artifactId>cxf-codegen-plugin</artifactId>??
???<version>2.7.6</version>??
???<executions>??
???????<execution>??
??????????<id>generate-sources</id>??
?????????<phase>generate-sources</phase>??
??????????<goals>??
?????????????<goal>wsdl2java</goal>??
??????????</goals>??
??????????<configuration>??
?????????????<wsdlOptions>??
????????????????<wsdlOption>??
???????????????????<wsdl>${basedir}/src/main/resources/HelloWorld.wsdl</wsdl>??
???????????????????<extraargs>??
??????????????????????<extraarg>-impl</extraarg>??
??????????????????????<extraarg>-server</extraarg>??
???????????????????</extraargs>??
????????????????</wsdlOption>??
?????????????</wsdlOptions>??
??????????</configuration>??
???????</execution>??
???</executions>??
</plugin>??
???????每一个extraarg元素代表一个参数,如果使用extraarg元素指定wsdl2java参数后面还带有参数值时,参数值也用一个extraarg来表示。如我们需要指定生成代码的包名时,我们的cxf-codegen-plugin应该这样声明:
<plugin>??
???<groupId>org.apache.cxf</groupId>??
???<artifactId>cxf-codegen-plugin</artifactId>??
???<version>2.7.6</version>??
???<executions>??
???????<execution>??
??????????<id>generate-sources</id>??
??????????<phase>generate-sources</phase>??
??????????<goals>??
?????????????<goal>wsdl2java</goal>??
??????????</goals>??
??????????<configuration>??
?????????????<wsdlOptions>??
????????????????<wsdlOption>??
???????????????????<wsdl>${basedir}/src/main/resources/HelloWorld.wsdl</wsdl>??
???????????????????<extraargs>??
??????????????????????<extraarg>-impl</extraarg>??
??????????????????????<extraarg>-server</extraarg>??
??????????????????????<extraarg>-p</extraarg><!--?指定包名,后面紧跟着的extraarg为对应的值?-->??
??????????????????????<extraarg>com.tiantian</extraarg>??
???????????????????</extraargs>??
????????????????</wsdlOption>??
?????????????</wsdlOptions>??
??????????</configuration>??
???????</execution>??
???</executions>??
</plugin>??
使用serviceName元素指定要生成Java代码的service
???????通过serviceName元素我们可以指定要针对当前wsdl文件里面的哪个service定义来生成文件。如:
<configuration>??
???<wsdlOptions>??
??????<wsdlOption>??
?????????<wsdl>${basedir}/src/main/resources/HelloWorld.wsdl</wsdl>??
?????????<!--?指定要生成代码的service名称?-->??
?????????<serviceName>HelloWorldImplService</serviceName>??
??????</wsdlOption>??
???</wsdlOptions>??
</configuration>??
使用wsdlRoot来指定wsdl文件存放的目录
???????我们知道在使用cxf-codegen-plugin的时候一个wsdlOption元素代表要生成的一个wsdl定义,当我们有多个wsdl文件时就需要定义多个wsdlOption,如:
<configuration>??
???<wsdlOptions>??
??????<wsdlOption>??
?????????<wsdl>${basedir}/src/main/resources/wsdl/HelloWorld.wsdl</wsdl>??
??????</wsdlOption>??
??????<wsdlOption>??
?????????<wsdl>${basedir}/src/main/resources/wsdl/HelloWorld2.wsdl</wsdl>??
??????</wsdlOption>??
???</wsdlOptions>??
</configuration>??
???????当我们的wsdl文件少的时候这样做还可以,但是当wsdl文件比较多的时候这样做就有点麻烦了。这个时候我们可以通过wsdlRoot元素来指定我们的wsdl文件存放的目录,cxf-codegen-plugin在扫描的时候只会扫描wsdlRoot指定的目录,而不会扫描其子目录。光指定了wsdlRoot还不能起作用,wsdlRoot必须和includes元素或者excludes元素配合使用。includes元素表示要包含哪些文件,而excludes元素表示要排除哪些文件。所以当我们要使用wsdl2java指定对wsdlRoot下的所有文件生成java代码时,我们可以这样做:
<configuration>??
???<wsdlRoot>${basedir}/src/main/resources/wsdl</wsdlRoot>??
???<includes>??
??????<include>*.wsdl</include>??
???</includes>??
</configuration>??
???????或者这样做:
<configuration>??
???<wsdlRoot>${basedir}/src/main/resources/wsdl</wsdlRoot>??
???<excludes>??
??????<exclude>null</exclude>??
???</excludes>??
</configuration>??
使用defaultOptions来指定公共的选项
???????当我们使用wsdlRoot元素来指定wsdl文件存放目录时,我们就不能再指定wsdl2java指令执行时的可选参数了。这个时候我们可以通过defaultOptions元素来指定。defaultOptions元素下指定的选项对所有的wsdlOption元素都会产生作用。如:
<configuration>??
???<defaultOptions>??
??????<extraargs>??
?????????<extraarg>-all</extraarg>??
??????</extraargs>??
???</defaultOptions>??
???<wsdlRoot>${basedir}/src/main/resources/wsdl</wsdlRoot>??
???<includes>??
??????<include>helloWorld.wsdl</include>??
???</includes>??
</configuration>??
?(本文首次发布于本人的iteye博客,http://elim.iteye.com/blog/1985995)
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!