如何在SpringMVC项目中部署WebService服务并打包生成客户端

场景

某SpringMVC项目原本为一个HTTP的WEB服务项目,之后想在该项目中添加WebService支持,使该项目同时提供HTTP服务和WebService服务。其中WebService服务通过 /ws/** 地址拦截。

配置

通过配置让SpringMVC支持WebService。

依赖

首先通过Maven引入必要依赖包。

  • org.apache.cxf
  • org.apache.neethi
  • com.ibm.wsdl4j
  • org.apache.XmlSchema

Web.xml

通过配置Web.xml使Spring框架具备WebService特性,这里通过添加Servlet(这里使用CXFServlet)实现。假设SpringMVC本身的DispatcherServlet已经启用,则在第2启动顺序添加CXFServlet。并添加servlet-mapping匹配请求。

配置如下

<!-- 在上下文中添加配置文件 -->
<context-param>
    <param-name>patchConfigLocation</param-name>
    <param-value>
        /WEB-INF/applicationServlet.xml
        /WEB-INF/webservice.xml
    <param-value>
</context-param>
<!-- 添加servlet -->
<servlet>
    <servlet-name>ws</servlet-name>
    <servlet-class>org.apache.cxf.trasport.servlet.CXFServlet</servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>ws</servlet-name>
    <url-pattern>/ws/**</url-pattern>
</servlet-mapping>

webservice.xml

将webservice的接口配置单独分离出来。配置如下:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:jaxws="http://cxf.apache.org/jaxws"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.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">
    <!-- cxf必要配置 -->
    <import resource="classpath:META-INF/cxf/cxf.xml" />
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
    <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />

    <!-- 接口的实现类声明 -->
    <jaxws:endpoint id="ticketDecodeAuthService"
        implementorClass="com.xxx.apps.web.ws.server.decode.XXXServiceImpl"
        address="/ticketDecodeAuth" />

</beans>

接口编写

对应上文声明的接口文档在写在相应的位置上(如本文例子则写在com.xxx.apps.web.ws.server.decode包中)

代码如下:

@WebService
@SOAPBinding(style = Style.RPC)
public interface XXXService {

    public WSReturn getAuth(String userName, String password) throws Exception;

}

接口实现类:

@WebService
@SOAPBinding(style = Style.RPC)
@SuppressWarnings("deprecation")
public class XXXServiceImpl implements XXXService {

    private static final Logger LOGGER = Logger.getLogger(XXXServiceImpl.class);

    @Override
    public WSReturn getAuth(String userName, String password) throws Exception {
        // WSReturn 是自定义的通用接口返回包装,可以用别的
        WSReturn res = new WSReturn();
        // TODO : your code here
        return res;
    }

}

发布接口效果

启动SpringMVC项目,根据配置文件定义,接口地址类似:http://ip:port/项目名/ws/**

若本例配置则有如下接口可以查看:

查看所有接口列表

http://ip:port/项目名/ws

某具体端口(XXXService)为例

这也是客户端调用时候的地址

http://ip:port/项目名/ws/XXXService?wsdl

这里可以看到端口的规范定义

客户端编写

客户端代码

通过CXF的动态代理方式编写,以反射方式将class直接引入可以实现统一调用方法。这样该Client即可调用任意接口。

代码如下:

/**
 * webservice服务客户端
 * @author WSY
 *
 */
public class WSClient {

        private static Logger logger = LoggerFactory.getLogger(WSClient.class);

        /**
         * 调用代理
         * @param cls 服务接口代理
         * @param method 方法名
         * @param wsdl wsdl地址
         * @param params 参数Object[]
         * @return
         * @throws Exception
         */
        @SuppressWarnings("rawtypes")
        public static WSReturn invoke(Class cls,String method,String wsdl, Object[] params) throws Exception{
            synchronized(WSClient.class){
                logger.info("[WSClient invoking] - class:"+cls.getName()+"; method:"+method+"; wsdl:"+
                        wsdl+"; params:"+getParams(params));

                JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
                factory.getInInterceptors().add(new LoggingInInterceptor());
                factory.getOutInterceptors().add(new LoggingOutInterceptor());
                factory.setServiceClass(cls);
                factory.setAddress(wsdl);
                Object cInstance = factory.create();
                Method invokeMethod = null;
                for(Method m : cls.getDeclaredMethods()){
                    if(m.getName().equalsIgnoreCase(method)){
                        invokeMethod = m;
                        break;
                    }
                }
                if(invokeMethod == null)
                    throw new Exception("ERROR:method not found");

                WSReturn res = (WSReturn) invokeMethod.invoke(cInstance, params);
                return res;
            }

            private static String getParams(Object[] params){
                StringBuilder sb = new StringBuilder("{");
                for(Object b : params){
                    sb.append(b).append(",");
                }
                if(sb.length()==1)
                    return "{}";
                else
                    return sb.substring(0,sb.length()-1)+"}";
            }
    }
}

打包

写个Ant脚本将一些必要的Java类和定义的Interface(不要打实现类)打成包。本文中将Client代码也写在了Service端了,所以将WSClient也一并打包进去。这样在编写对应的客户端时候,仅需专注于功能实现即可。

<?xml version="1.0"?>
<project name="tws-interfaces" default="jar" basedir=".">

    <!-- Give user a chance to override without editing this file or typing -D -->
    <property name="coredir" location="." />
    <property name="classdir" location="${basedir}/target/classes" />

    <target name="jar" description="Build the jars for core">
        <delete file="${coredir}/webservice-interfaces-1.0.jar" />
        <jar destfile="${coredir}/webservice-interfaces-1.0.jar">
            <fileset dir="${classdir}">
                <include name="**/com/xxx/apps/web/ws/server/**/*Service.class" />
                <include name="**/com/xxx/apps/web/ws/server/tokenservice/**/*.class" />
                <include name="**/com/xxx/apps/web/ws/server/WSReturn.class"/>
                <include name="**/com/xxx/apps/comm/ResultState.class"/>
                <include name="**/com/xxx/apps/web/ws/server/wsclient/WSClient.class"/>
                <include name="**/com/xxx/apps/comm/RespResult.class"/>
                <exclude name="**/com/xxx/apps/web/ws/server/**/*Impl.class" />
            </fileset>
        </jar>
        <copy todir="../xxxclient/lib" file="./webservice-interfaces-1.0.jar"></copy>
    </target>

</project>

客户端项目实现

依赖

首先通过Maven引入必要依赖包。

  • org.apache.cxf.cxf-rt-frontend-jaxws
  • org.apache.cxf.cxf-rt-databinding-aegis
  • org.apache.cxf.cxf-rt-transports-http
  • org.apache.cxf.cxf-rt-transports-http-jetty
  • commons-codec.commons-codec

    最重要的:引入server端打包好的jar包,里边有WSClient和必要的接口

        <dependency>
            <groupId>com.xxx</groupId>
            <artifactId>xxxserver</artifactId>
            <version>1.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/lib/webservice-interfaces-1.0.jar</systemPath>
        </dependency>
    
    

WSClient调用

通过直接调用jar包中的WSClient即可调用远程WebService接口。

调用示例代码如下:

/** 这里将调用注释复制过来
     * 调用代理
     * @param cls 服务接口代理
     * @param method 方法名
     * @param wsdl wsdl地址
     * @param params 参数Object[]
     * @return
     * @throws Exception
     */
WSReturn res= WSClient.invoke(XXXService.class
                , "getAuth"
                ,endpoints.get(XXXService.class.getName())
                , new Object[]{"admin","admin"});
        if(token.getStatusId() == ResultState.SUCESS){
            tokenValue = (String) token.getMap().get("token");
        } else {
            logger.error("获取token失败:"+token.getMsg());
        }

一些坑

一定要引入cxf的必要配置

虽然在项目中看不到,但是这些xml文件在cxf的jar包中。

    <!-- cxf必要配置 -->
    <import resource="classpath:META-INF/cxf/cxf.xml" />
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
    <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />

Interface的类路径一定要统一

如服务端的 XXXService.javacom.xxx.web.ws.server 中,则在客户端的XXXService.java类也应该在相同的路径即: com.xxx.web.ws.server 。 所以为方便起见,用Ant直接打包比较方便,不容易错。

客户端并发问题

本例中调用WSClient,通过反射机制调用,共用一个Factory,因此在并发时候容易出现问题,需要在WSClient中加锁

原文地址:https://blog.csdn.net/tzdwsy/article/details/51938786

原文地址:https://www.cnblogs.com/jpfss/p/11065557.html

时间: 2024-10-25 12:40:31

如何在SpringMVC项目中部署WebService服务并打包生成客户端的相关文章

JAVA项目中公布WebService服务——简单实例

1.在Java项目中公布一个WebService服务: 怎样公布? --JDK1.6中JAX-WS规范定义了怎样公布一个WebService服务. (1)用jdk1.6.0_21以后的版本号公布. (2)与Web服务相关的类,都位于Javax.jws.*包中 @WebService--此注解用在类上指定将此类公布成一个WebService: EndPoint--此类为端点服务类,当中publish()方法用于将一个已经加入了@WebService注解对象绑定到一个地址的port上,用于公布. 2

JAVA项目中发布WebService服务——简单实例

1,在Java项目中发布一个WebService服务: 如何发布? --JDK1.6中JAX-WS规范定义了如何发布一个WebService服务: (1)用jdk1.6.0_21以后的版本发布: (2)与Web服务相关的类,都位于Javax.jws.*包中 @WebService--此注解用在类上指定将此类发布成一个WebService: EndPoint--此类为端点服务类,其中publish()方法用于将一个已经添加了@WebService注解对象绑定到一个地址的端口上,用于发布. 2,例子

在java web项目中集成webservice

公司要求在项目中加入webservice服务,因为项目中使用了spring框架,所以在这里使用与spring兼容性较好的cxf来实现 cxf所需jar包 spring的jar包就不贴了 一:创建webservice服务器 1)创建一个服务接口 package com.service; import javax.jws.WebParam; import javax.jws.WebService; @WebService public interface IHelloWorld { public S

如何在asp.net的mvc类型项目中添加webservice

先在项目中添加webservice 会产生一个asmx结尾的文件,然后在其cs中写方法. 另外在global.asax.cs里或App_Start/Route_Config中加一句 routes.IgnoreRoute("{resource}.asmx/{*pathInfo}"); 这样asmx后缀的web service就不会被mvc的routing来处理了.

Jboss7.1中部署webservice的问题-1

(1)使用web容器模式在jboss中部署web service 通常会报无法找到相应的类的错误,(这里如果没有web.xml的话就无法部署也不会出现下面错误) Not installing optional component org.jboss.as.quickstarts.wshelloworld.OrderServiceImpl due to exception: java.lang.ClassNotFoundException: org.jboss.as.quickstarts.wsh

java web项目(spring项目)中集成webservice ,实现对外开放接口

什么是WebService?webService小示例 点此了解 下面进入正题: Javaweb项目(spring项目)中集成webservice ,实现对外开放接口步骤: 准备: 采用与spring兼容性较好的cxf来实现 cxf 的  jar下载地址: http://cxf.apache.org/download.html 选择zip格式下载,解压后的lib目录下的jar 需要最少的jar如下: cxf-2.3.3.jargeronimo-annotation_1.0_spec-1.1.1.

如何在Vue项目中使用vw实现移动端适配

https://www.w3cplus.com/mobile/vw-layout-in-vue.html  原文网址 如何在Vue项目中使用vw实现移动端适配 作者:大漠 日期:2018-01-25 点击:10362 vw Layout 布局 Vue mobile 编辑推荐:使用 Coding.net 搭建静态博客,自定义域名,全站 HTTPS 加密,自动实时部署, 立即托管您的网站! 有关于移动端的适配布局一直以来都是众说纷纭,对应的解决方案也是有很多种.在<使用Flexible实现手淘H5页

IIS Internal Server Error &amp;IIS8中部署WCF服务出错:HTTP 错误 404.3 - Not Found

Http error      503. The service is unavailable. Due to appliction pool is stop and start it can resolve it Server Error Internet Information Services 7.5 Error Summary HTTP Error 500.19 - Internal Server Error The requested page cannot be accessed b

项目记录:spring+springmvc 项目中 @Transactional 失效的解决方法

第一步,修改spring的配置文件和springmvc的配置文件 --------------------------------applicationContext.xml <context:annotation-config/>  <context:component-scan base-package="com.xxx"> <context:exclude-filter type="annotation" expression=&