• 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;
    
    @WebService
    public 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%injava"  
        set tempclass="%JAVA_HOME%libdt.jar";"%JAVA_HOME%lib	ools.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.WebServiceApp
    
    endlocal

    start.sh

    #!/bin/bash
    LIB_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/sh
    APP_MAIN=com.lglan.webservice.server.app.WebServiceApp
    
    tradePortalPID=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="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/1pJt52Rp

    三.参考

    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

    全文完…

  • 相关阅读:
    Python-产生随机长度的密码
    Python-双色球
    Python-产生手机号码
    Word操作笔记
    1035 最长的循环节
    B. Recover the String
    uva11752 The Super Powers
    UVA11754
    GCD
    D. Persistent Bookcase(Codeforces Round #368 (Div. 2))
  • 原文地址:https://www.cnblogs.com/beetle-shu/p/4100761.html
Copyright © 2020-2023  润新知