Web Service ---- CXF + SPRING 开发 SOAP服务
2016-09-21 17:34
609 查看
项目目录视图:
依赖架包:
源码:
WS 接口: HelloService.javapackage service; import javax.jws.WebService; @WebService public interface HelloService { String say(String name); }
WS 接口实现类:HelloServiceImpl.java
package service; import javax.jws.WebService; @WebService public class HelloServiceImpl implements HelloService { public String say(String name) { return "hello " + name; } }
JaxWsServer 类来发布 WS: JaxWsServer.java
package service; import org.apache.cxf.frontend.ServerFactoryBean; import org.apache.cxf.jaxws.JaxWsServerFactoryBean; public class JaxWsServer { public static void main(String[] args) { //ServerFactoryBean factory = new ServerFactoryBean(); JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean(); factory.setAddress("http://localhost:8080/ws/soap/hello"); factory.setServiceClass(HelloService.class); factory.setServiceBean(new HelloServiceImpl()); factory.create(); System.out.println("soap ws is published"); } }
运行 JaxWsServer 类
浏览器访问:http://localhost:8080/ws/soap/hello?wsdl, 输出如下内容,则部署成功。
客户端访问WS:
方案一: CXF静态代理客户端import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; public class JaxWsClient { public static void main(String[] args) { JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.setAddress("http://localhost:8080/ws/soap/hello"); factory.setServiceClass(HelloService.class); HelloService helloService = factory.create(HelloService.class); String result = helloService.say("world"); System.out.println(result); } }
方案二: CXF动态代理客户端
import org.apache.cxf.endpoint.Client; import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; public class JaxWsDynamicClient { public static void main(String[] args) { JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance(); Client client = factory.createClient("http://localhost:8080/ws/soap/hello?wsdl"); try { Object[] results = client.invoke("say", "world"); System.out.println(results[0]); } catch (Exception e) { e.printStackTrace(); } } }
方案三:通用动态代理客户端
import org.apache.cxf.endpoint.Client; import org.apache.cxf.endpoint.dynamic.DynamicClientFactory; public class DynamicClient { public static void main(String[] args) { DynamicClientFactory factory = DynamicClientFactory.newInstance(); Client client = factory.createClient("http://localhost:8080/ws/soap/hello?wsdl"); try { Object[] results = client.invoke("say", "world"); System.out.println(results[0]); } catch (Exception e) { e.printStackTrace(); } } }
方案四:基于 CXF simple 方式的客户端
import org.apache.cxf.frontend.ClientProxyFactoryBean; public class SimpleClient { public static void main(String[] args) { ClientProxyFactoryBean factory = new ClientProxyFactoryBean(); factory.setAddress("http://localhost:8080/ws/soap/hello"); factory.setServiceClass(HelloService.class); HelloService helloService = factory.create(HelloService.class); String result = helloService.say("world"); System.out.println(result); } }
方案五:基于 Spring 的客户端
方法一:使用 JaxWsProxyFactoryBean
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="factoryBean" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean"> <property name="serviceClass" value="demo.ws.soap_spring_cxf.HelloService"/> <property name="address" value="http://localhost:8080/ws/soap/hello"/> </bean> <bean id="helloService" factory-bean="factoryBean" factory-method="create"/> </beans>
方法二:使用 jaxws:client(推荐)
<?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:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <jaxws:client id="helloService" serviceClass="demo.ws.soap_spring_cxf.HelloService" address="http://localhost:8080/ws/soap/hello"/> </beans>
客户端代码
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Client { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring-client.xml"); HelloService helloService = context.getBean("helloService", HelloService.class); String result = helloService.say("world"); System.out.println(result); } }
WEB容器中部署 Spirng + CXF 开发的WS服务
配置 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_3_0.xsd" version="3.0"> <!-- Spring --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- CXF --> <servlet> <servlet-name>cxf</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>cxf</servlet-name> <!-- 所有带有 /ws 前缀的请求,将会交给被 CXFServlet 进行处理,也就是处理 WS 请求了。目前主要使用了 Spring IOC 的特性,利用了 ContextLoaderListener 加载 Spring 配置文件,即这里定义的 spring.xml 文件。 --> <url-pattern>/ws/*</url-pattern> </servlet-mapping> </web-app>
配置spring.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-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <context:component-scan base-package="demo.ws"/> <import resource="spring-cxf.xml"/> </beans>
以上配置做了两件事情:
1、定义 IOC 容器扫描路径,即这里定义的 demo.ws,在这个包下面(包括所有子包)凡是带有 Component 的类都会扫描到 Spring IOC 容器中。
2、 引入 spring-cxf.xml 文件,用于编写 CXF 相关配置。将配置文件分离,是一种很好的开发方式。
配置 spring-cxf.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:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <jaxws:server id="helloService" address="/soap/hello"> <jaxws:serviceBean> <ref bean="helloServiceImpl"/> </jaxws:serviceBean> </jaxws:server> </beans>
通过 CXF 提供的 Spring 命名空间,即 jaxws:server,来发布 WS。其中,最重要的是 address 属性,以及通过 jaxws:serviceBean 配置的 Spring Bean。
可见,在 Spring 中集成 CXF 比想象的更加简单,此外,还有一种更简单的配置方法,那就是使用 CXF 提供的 endpoint 方式,配置如下:
<?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:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <jaxws:endpoint id="helloService" implementor="#helloServiceImpl" address="/soap/hello"/> </beans>
使用 jaxws:endpoint 可以简化 WS 发布的配置,与 jaxws:server 相比,确实是一种进步。
注意:这里的 implementor 属性值是 #helloServiceImpl,这是 CXF 特有的简写方式,并非是 Spring 的规范,意思是通过 Spring 的 Bean ID 获取 Bean 实例。
同样,也可以在 Spring 中使用 simple 方式来发布 WS,配置如下:
<?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:simple="http://cxf.apache.org/simple" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://cxf.apache.org/simple http://cxf.apache.org/schemas/simple.xsd"> <simple:server id="helloService" serviceClass="#helloService" address="/soap/hello"> <simple:serviceBean> <ref bean="#helloServiceImpl"/> </simple:serviceBean> </simple:server> </beans>
可见,simple:server 与 jaxws:server 的配置方式类似,都需要配置一个 serviceBean。
比较以上这三种方式,我个人更加喜欢第二种,也就是 endpoint 方式,因为它够简单!
至于为什么 CXF 要提供如此之多的 WS 发布方式?我个人认为,CXF 为了满足广大开发者的喜好,也是为了向前兼容,所以这些方案全部保留下来了。
启动 Tomcat
将应用部署到 Tomcat 中,在浏览器中http://localhost:8080/ws
通过以上过程,可以看出 CXF 完全具备 RI 的易用性,并且与 Spring 有很好的可集成性,而且配置也非常简单。
同样通过这个地址可以查看 WSDL:http://localhost:8080/ws/soap/hello?wsdl
注意:紧接在 /ws 前缀后面的 /soap/hello,其实是在 address=”/soap/hello” 中配置的。
现在已经成功地通过 CXF 对外发布了 WS,下面要做的事情就是用 WS 客户端来调用这些 endpoint 了。
您可以不再使用 JDK 内置的 WS 客户端,也不必通过 WSDL 打客户端 jar 包,因为 CXF 已经为您提供了多种 WS 客户端解决方案,根据您的口味自行选择吧!
Cxf工具
java2ws通过该工具我们可以根据SEI(Service Endpoint Implementation的缩写)类及其相关的类来生成WebService的服务端、客户端和wsdl文件等。SEI需要是使用了@WebService标注的Service接口或类。
在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文件)
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>
使用cxf-java2ws-plugin插件生成的Java代码默认会放在项目的根目录下。
对于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
wsdl2java工具
wsdl2java是CXF自带的工具,在CXF根目录下的bin目录下。我们可以在命令行使用这一工具。就可以通过wsdl文件生成对应的Java代码,包括WebService的Service类定义、服务端代码、客户端代码。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实现类的时候只会生成基本的代码结构,至于里面的操作的具体逻辑还需要我们自己来实现。
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指令的其他参数可以通过:
<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>
每一个extraarg元素代表一个参数,如果使用extraarg元素指定wsdl2java参数后面还带有参数值时,参数值也用一个extraarg来表示
使用serviceName元素指定要生成Java代码的service
<configuration> <wsdlOptions> <wsdlOption> <wsdl>${basedir}/src/main/resources/HelloWorld.wsdl</wsdl> <!-- 指定要生成代码的service名称 --> <serviceName>HelloWorldImplService</serviceName> </wsdlOption> </wsdlOptions> </configuration>
使用wsdlRoot来指定wsdl文件存放的目录
configuration> <wsdlRoot>${basedir}/src/main/resources/wsdl</wsdlRoot> <!-- 包含 --> <includes> <include>*.wsdl</include> </includes> <!-- 不包含 --> <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>
相关文章推荐
- Web Service那些事 2/4 - 使用 CXF 开发 SOAP 服务
- Web Service 那点事儿(2)—— 使用 CXF 开发 SOAP 服务
- Web Service 那点事儿(2)—— 使用 CXF 开发 SOAP 服务
- Web Service 那点事儿(2)—— 使用 CXF 开发 SOAP 服务
- SpringBoot + CXF 开发Web Service 服务
- Web Service 那点事儿(2)—— 使用 CXF 开发 SOAP 服务
- CXF 开发SOAP WebService服务(Spring+多种形式)
- Web Service 那点事儿(4)—— 使用 CXF 开发 REST 服务
- CXF与Spring整合开发WebService服务
- CXF Spring开发WebService,基于SOAP和REST方式
- webService(CXF开发SOAP应用,CXF整合spring)未完待续
- Webservice的cxf开发_使用spring发布服务+ajax调用服务
- Web Service 那点事儿(4)—— 使用 CXF 开发 REST 服务
- 使用CXF开发Web Service服务
- 9.Web Service Spring整合CXF之发布服务
- WebService(4):CXF Spring开发WebService,基于SOAP和REST方式
- cxf和spring开发web service--服务器端
- 使用CXF和Spring发布Soap服务
- WebService-04-CXF与Spring集成开发WebService服务
- 用cxf+spring开发web service