首页 > 代码库 > WebService的发布及客户端的调用

WebService的发布及客户端的调用

一.目录

1.JAX-WS发布WebService

1.1 创建一个简单的WS

1.2 打包部署和发布

2.CXF+Spring发布WebService

3.客户端的调用方式

二.正文

1. JAX-WS发布WebService

JAX-WS (Java API for XML Web Services) 是一组专门用于实现 XML Web Services 的 Java API。JDK 1.6 自带 JAX-WS 版本为 2.1。不过,JAX-WS 只提供 web services 的基础功能,所以如果你希望实现 web services 的复杂功能,比如 WS-Security,WS-Policy,WS-RM 等,那就需要切换到 Apache CXF 、Metro 或者 Axis。

1.1 创建一个简单的WebService

首先,还是来看一下jdk API1.7中javax.jws包下面关于注解@WebService的描述吧。它是用来标记一个被定义为Web Service的实现类或接口的。元素endpointInterface是用来指明服务端接口的。这就是我们在定义接口和实现的时候要用的了。

image

接着,新建一个Java项目,定义好服务接口和具体实现类,如下:

package com.lglan.webservice.server;import javax.jws.WebService;@WebServicepublic interface GreetingService {    public String greeting(String userName);}
package com.lglan.webservice.server.impl;import java.util.Calendar;import javax.jws.WebService;import com.lglan.webservice.server.GreetingService;@WebService(endpointInterface="com.lglan.webservice.server.GreetingService")public class GreetingServiceImpl implements GreetingService {    public String greeting(String userName) {        // TODO Auto-generated method stub        return "Hello " + userName + ", currentTime is "        + Calendar.getInstance().getTime();    }}

最后,就是来发布服务了,这里用到了javax.xml.ws.Endpoint类的publish方法,详见API文档

public static Endpoint publish(String address,               Object implementor)
Creates and publishes an endpoint for the specified implementor object at the given address.
package com.lglan.webservice.server.app;import javax.xml.ws.Endpoint;import com.lglan.webservice.server.impl.GreetingServiceImpl;public class WebServiceMain {        public static void main(String[] args) {        System.out.println("web service start");        GreetingServiceImpl implementor= new GreetingServiceImpl();        String address="http://localhost:8080/greetingService";        Endpoint.publish(address, implementor);        System.out.println("web service started");    }}

运行上面的类,在浏览器中请求http://localhost:8080/greetingService?wsdl就能看到我们发布的webservice接口了。

1.2 打包部署和发布

以上我们是通过在IDE中直接执行java application来发布服务的,那如何把项目进行打包部署呢?当然,最常见的方法就是把项目发布成web项目然后在web容器中启动(该方法在第二部分介绍)。这里,最简单的方法就是在jre中直接运行编译后的WebServiceMain.class文件,跟我们在IDE中一样,不需要容器,只要有jre环境就行。

用maven的assembly插件来打包是最方便的了(当然,要用maven来管理项目,用maven谁用谁知道),只要在项目的pom.xml中配置assembly插件,然后在assembly.xml中描述你想要怎么打包就行了。

pom.xml的<plugins></plugins>节点中加入:

<plugin>    <artifactId>maven-assembly-plugin</artifactId>    <configuration> <!--描述文件路径-->        <descriptor>src/main/assembly/assembly.xml</descriptor>    </configuration>    <executions> <!--执行器 mvn assembly:assembly-->        <execution>            <id>make-assembly</id> <!--名字任意 -->            <phase>package</phase> <!-- 绑定到package生命周期阶段上 -->            <goals>                <goal>single</goal> <!-- 只运行一次 -->             </goals>        </execution>    </executions></plugin>

assembly.xml

<?xml version="1.0" encoding="UTF-8"?><assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">    <id>assembly</id>    <formats>        <format>zip</format>    </formats>    <includeBaseDirectory>true</includeBaseDirectory>    <fileSets>        <fileSet>            <directory>src/main/assembly/bin</directory><!-- 源路径 -->            <outputDirectory>bin</outputDirectory><!-- 输出路径 -->            <fileMode>0755</fileMode><!-- 文件权限rwx -->        </fileSet>        <fileSet>            <directory>src/main/resources</directory>            <outputDirectory>conf</outputDirectory>            <fileMode>0644</fileMode>        </fileSet>    </fileSets>    <dependencySets>        <dependencySet>            <outputDirectory>lib</outputDirectory>        </dependencySet>    </dependencySets></assembly>

执行maven install 或 package命令后,项目会被打包成三个文件夹:/bin, /conf, /lib,其中/conf下面放的是配置文件,/lib下面放的是项目依赖的所有的jar包(包括项目自身的jar包)。那么,/bin目录下是什么呢?这里放的是我们自己编写的用来启动和停止服务的脚本,例如:windows下面的.bat文件和Unix或Linux下的.sh脚本文件。好吧,我们就来写启动脚本吧,在项目中新建src/main/assembly/bin路径,创建脚本如下:

start.bat (其中goto start … :start中间代码是被跳过的,这里用这种方法来达到注掉一段代码的目的了,眨眼)

@echo off  setlocal enabledelayedexpansion  goto start    ::方法一,用start命令来启动java.exe    echo %JAVA_HOME%      set jre="%JAVA_HOME%\bin\java"      set tempclass="%JAVA_HOME%\lib\dt.jar";"%JAVA_HOME%\lib\tools.jar";    cd ..\lib    for %%i in (*) do set tempclass=!tempclass!;%%i;    start "GreetingService" %jre% -classpath !tempclass! com.lglan.webservice.server.app.WebServiceApp  :start::方法二,本地配置好jdk的环境变量,直接执行java指令set LIB_JARS=""cd ..\lib  for %%i in (*) do set LIB_JARS=!LIB_JARS!;..\lib\%%i;java -Xms64m -Xmx1024m -XX:MaxPermSize=64M -classpath ..\conf;%LIB_JARS% com.lglan.webservice.server.app.WebServiceAppendlocal

start.sh

#!/bin/bashLIB_JARS=.  for i in ls lib/*.jar   do   LIB_JARS=$LIB_JARS:./lib/$i  done  $JAVA_HOME/bin/java -classpath $LIB_JARS com.lglan.webservice.server.app.WebServiceApp

stop.sh

#!/bin/shAPP_MAIN=com.lglan.webservice.server.app.WebServiceApptradePortalPID=0 getTradeProtalPID(){    javaps=`$JAVA_HOME/bin/jps -l | grep $APP_MAIN`    if [ -n "$javaps" ]; then        tradePortalPID=`echo $javaps | awk {print $1}`    else        tradePortalPID=0    fi}shutdown(){    getTradeProtalPID    echo "========================================================================================"    if [ $tradePortalPID -ne 0 ]; then        echo -n "Stopping $APP_MAIN(PID=$tradePortalPID)..."        kill -9 $tradePortalPID        if [ $? -eq 0 ]; then            echo "[Success]"            echo "================================================================================"        else            echo "[Failed]"            echo "================================================================================"        fi        getTradeProtalPID        if [ $tradePortalPID -ne 0 ]; then            shutdown        fi    else        echo "$APP_MAIN is not running"        echo "===================================================================================="    fi}shutdown

好了,按照上面的方法用maven打个包,解压之后,在相应的操作系统下执行start脚本就可以发布服务了。

2.CXF+Spring发布WebService

首先,要导入依赖的jar包,直接在pom.xml的<dependencies></dependencies>中添加

<dependency>    <groupId>org.apache.cxf</groupId>    <artifactId>cxf-api</artifactId>    <version>2.5.0</version></dependency><dependency>    <groupId>org.apache.cxf</groupId>    <artifactId>cxf-rt-frontend-jaxws</artifactId>    <version>2.5.0</version></dependency><dependency>    <groupId>org.apache.cxf</groupId>    <artifactId>cxf-rt-bindings-soap</artifactId>    <version>2.5.0</version></dependency><dependency>    <groupId>org.apache.cxf</groupId>    <artifactId>cxf-rt-transports-http</artifactId>    <version>2.5.0</version></dependency><dependency>    <groupId>org.apache.cxf</groupId>    <artifactId>cxf-rt-ws-security</artifactId>    <version>2.5.0</version></dependency><dependency>    <groupId>org.apache.cxf</groupId>    <artifactId>cxf-rt-transports-http-jetty</artifactId>    <version>2.4.6</version></dependency>

通过Spring来管理服务类,由cxf的jaxws.xsd定义了服务端的节点jaxws: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:context="http://www.springframework.org/schema/context"    xmlns:tx="http://www.springframework.org/schema/tx"    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://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd        http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">    <context:annotation-config/>    <context:component-scan base-package="com.lglan.webservice.server"/>      <jaxws:endpoint id="GreetingService" implementor="com.lglan.webservice.server.impl.GreetingServiceImpl" address="http://localhost:8080/greetingService" />     </beans>

配置完成了,接下来写个main方法来启动服务吧。

package com.lglan.webservice.server.app;import org.springframework.context.support.ClassPathXmlApplicationContext;public class WebServiceStart {        public static void main(String[] args) throws Exception {        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("classpath:cxf-spring.xml");        ac.start();        System.in.read();    }}

直接运行上面的类,在浏览器中输入http://localhost:8080/greetingService?wsdl就能看到发布成功了。

当然,这里还可以通过cxf-rt-frontend-jaxws包下面的org.apache.cxf.jaxws.JaxWsServerFactoryBean来创建服务,不需要在spring配置中添加服务类的bean了,代码如下:

package com.lglan.webservice.server.app;import org.apache.cxf.endpoint.Server;import org.apache.cxf.jaxws.JaxWsServerFactoryBean;import com.lglan.webservice.server.impl.GreetingServiceImpl;public class WebServiceMain2 {        public static void main(String[] args) {        //工厂模式创建jax        JaxWsServerFactoryBean jwsFactoryBean = new JaxWsServerFactoryBean();        jwsFactoryBean.setServiceClass(GreetingServiceImpl.class);        jwsFactoryBean.setAddress("http://localhost:8080/greetingService");        //获取一个server对象,并启动        Server server = jwsFactoryBean.create();        server.start();            }}

最后再讲一下怎么在web容器中发布Web Service :

第一步:将原来的Java项目转成Web项目,具体步骤请参考:

http://blog.sina.com.cn/s/blog_7deb4bd601019llp.html

第二步:项目的根路径下(这里对应webapp目录)添加web.xml文件

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns="http://java.sun.com/xml/ns/javaee"     xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"    xsi:schemaLocation="    http://java.sun.com/xml/ns/javaee     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">    <context-param>        <param-name>contextConfigLocation</param-name>        <param-value>classpath:cxf-spring.xml</param-value><!-- 这里指定spring配置文件 -->    </context-param>    <listener>        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>    </listener>    <servlet>        <servlet-name>cxf</servlet-name>        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>        <load-on-startup>1</load-on-startup>    </servlet>    <servlet-mapping>        <servlet-name>cxf</servlet-name>        <url-pattern>/services/*</url-pattern>    </servlet-mapping>    <welcome-file-list>        <welcome-file>index.html</welcome-file>    </welcome-file-list></web-app>

还有,不要忘记修改原endpoint节点的address,在cxf-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"    xmlns:tx="http://www.springframework.org/schema/tx"    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://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd        http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">    <context:annotation-config/>    <context:component-scan base-package="com.lglan.webservice.server"/>      <jaxws:endpoint id="GreetingService" implementor="com.lglan.webservice.server.impl.GreetingServiceImpl" address="/greetingService" />     </beans>

第三步,在tomcat中启动项目,访问配置的服务路径http://localhost:8080/cxf_ws_demo/services/greetingService?wsdl,发布成功!

image

二.客户端的调用方式

上面讲服务发布的方法,提到了三种:javax.xml.ws.Endpoint类的publish方法;cxf-rt-frontend-jaxws包下面的org.apache.cxf.jaxws.JaxWsServerFactoryBean类来创建服务;在spring配置文件中配置服务类。那么,客户端的调用也有类似的几种方法。

在写实现调用的方法之前,我们先来搭建一个客户端项目,在IDE中建一个maven管理的Java项目,pom文件中加了cxf依赖的jar包(同服务端,可选),cmd中执行cxf指令:wsdl2java –d D:\client –client http://localhost:8080/greetingService?wsdl,导入刚才cxf生成的客户端依赖包,准备工作完成。

方法1:继承javax.xml.ws.service类来创建service实例,该service类为我们提供了一个service()方法来获得服务,然后提供getPort()方法来动态调用服务接口。可喜的是,这个类完全不用我们自己来写,通过上面cxf指令生成的客户端代码包中已经给我们建好了,我们只要拿来用就行了。此例中,service类代码如下:

package com.lglan.webservice.server.impl;import java.net.MalformedURLException;import java.net.URL;import javax.xml.namespace.QName;import javax.xml.ws.WebEndpoint;import javax.xml.ws.WebServiceClient;import javax.xml.ws.WebServiceFeature;import com.lglan.webservice.server.GreetingService;import javax.xml.ws.Service;/** * This class was generated by Apache CXF 2.2.8 * Sat Nov 15 20:17:20 CST 2014 * Generated source version: 2.2.8 *  */@WebServiceClient(name = "GreetingServiceImplService",                   wsdlLocation = "http://localhost:8080/greetingService?wsdl",                  targetNamespace = "http://impl.server.webservice.lglan.com/") public class GreetingServiceImplService extends Service {    public final static URL WSDL_LOCATION;    public final static QName SERVICE = new QName("http://impl.server.webservice.lglan.com/", "GreetingServiceImplService");    public final static QName GreetingServiceImplPort = new QName("http://impl.server.webservice.lglan.com/", "GreetingServiceImplPort");    static {        URL url = null;        try {            url = new URL("http://localhost:8080/greetingService?wsdl");        } catch (MalformedURLException e) {            System.err.println("Can not initialize the default wsdl from http://localhost:8080/greetingService?wsdl");            // e.printStackTrace();        }        WSDL_LOCATION = url;    }    public GreetingServiceImplService(URL wsdlLocation) {        super(wsdlLocation, SERVICE);    }    public GreetingServiceImplService(URL wsdlLocation, QName serviceName) {        super(wsdlLocation, serviceName);    }    public GreetingServiceImplService() {        super(WSDL_LOCATION, SERVICE);    }    /**     *      * @return     *     returns GreetingService     */    @WebEndpoint(name = "GreetingServiceImplPort")    public GreetingService getGreetingServiceImplPort() {        return super.getPort(GreetingServiceImplPort, GreetingService.class);    }    /**     *      * @param features     *     A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy.  Supported features not in the <code>features</code> parameter will have their default values.     * @return     *     returns GreetingService     */    @WebEndpoint(name = "GreetingServiceImplPort")    public GreetingService getGreetingServiceImplPort(WebServiceFeature... features) {        return super.getPort(GreetingServiceImplPort, GreetingService.class, features);    }}

好了,我们可以通过以上类来获得服务接口并调用了,方法如下:

package com.lglan.webservice.client;import java.net.URL;import com.lglan.webservice.server.GreetingService;import com.lglan.webservice.server.impl.GreetingServiceImplService;public class TestGreetingService3 {    public static void main(String[] args) throws Exception {        GreetingServiceImplService gs = new GreetingServiceImplService(new URL("http://localhost:8080/cxf_ws_demo/services/greetingService?wsdl"));        GreetingService port = gs.getGreetingServiceImplPort();        System.out.println(port.greeting("World"));    }}

方法2:通过cxf-rt-frontend-jaxws包下面的org.apache.cxf.jaxws.JaxWsProxyFactoryBean类来获取客户端的代理类并创建服务接口,实现方法如下:

package com.lglan.webservice.client;import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;  import com.lglan.webservice.server.GreetingService;  public class TestGreetingService {      public static void main(String[] args) {          //创建WebService客户端代理工厂          JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();          //注册WebService接口          factory.setServiceClass(GreetingService.class);          //设置WebService地址          factory.setAddress("http://localhost:8080/cxf_ws_demo/services/greetingService?wsdl");          GreetingService greetingService = (GreetingService)factory.create();          System.out.println("invoke webservice...");          System.out.println("message context is:"+greetingService.greeting("World"));         }  }

方法3:spring配置服务接口的bean

客户端添加spring的配置文件wsdl-service.xml,在<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:context="http://www.springframework.org/schema/context"    xmlns:tx="http://www.springframework.org/schema/tx"    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://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd        http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">    <context:annotation-config/>    <context:component-scan base-package="com.lglan.webservice.server"/>         <jaxws:client id="GreetingService" serviceClass="com.lglan.webservice.server.GreetingService"                     address="http://localhost:8080/cxf_ws_demo/services/greetingService?wsdl"/>                    <!--   <bean id="proxyFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">    <property name="serviceClass"     value="http://www.mamicode.com/com.lglan.webservice.server.GreetingService"/>    <property name="address"         value="http://localhost:8080/cxf_ws_demo/services/greetingService?wsdl"/>       </bean>   <bean id="GreetingService" class="com.lglan.webservice.server.GreetingService"    factory-bean="proxyFactory" factory-method="create"/> --></beans>

最后,通过读spring的配置文件来实例化服务接口类并调用服务提供的方法:

package com.lglan.webservice.client;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.lglan.webservice.server.GreetingService;public class TestGreetingService2 {    public static void main(String[] args) {        ApplicationContext ac = new ClassPathXmlApplicationContext("wsdlService.xml");        GreetingService greeting = (GreetingService) ac.getBean("GreetingService");        System.out.println(greeting.greeting("World"));    }}

总之,客户端调用服务的方式有很多,可以按照自己的喜欢来,不用关心服务端是如何实现的。关于客户端的调用最近计划整理一篇接口测试客户端搭建的文章,更多内容就在那里详述吧。

附:demo源码地址 http://pan.baidu.com/s/1o69LtME

三.参考

webservice:

http://cxf.apache.org/docs/a-simple-jax-ws-service.html

http://cxf.apache.org/docs/writing-a-service-with-spring.html

http://blessht.iteye.com/blog/1105562/

http://www.ithov.com/linux/125942.shtml

http://www.cnblogs.com/doosmile/archive/2012/06/21/2557351.html

http://www.blogjava.net/icewee/archive/2012/07/06/382399.html

http://www.cnblogs.com/frankliiu-java/articles/1641949.html

打包部署:

http://blog.csdn.net/WANGYAN9110/article/details/38646677

http://maven.apache.org/plugins/maven-assembly-plugin/assembly.html

http://menjoy.iteye.com/blog/382200

http://blog.csdn.net/junmuzi/article/details/12239303

http://blog.csdn.net/jadyer/article/details/7960802

http://blog.sina.com.cn/s/blog_7deb4bd601019llp.html

 

全文完…

WebService的发布及客户端的调用