场景

某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

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

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

    1.在Java项目中公布一个WebService服务: 怎样公布? --JDK1.6中JAX-WS规范定义了怎样公布一个WebService服务. (1)用jdk1.6.0_21以后的版本号公布. ( ...

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

    什么是WebService?webService小示例 点此了解 下面进入正题: Javaweb项目(spring项目)中集成webservice ,实现对外开放接口步骤: 准备: 采用与spring ...

  3. 如何在maven项目中使用spring

    今天开始在maven项目下加入spring. 边学习边截图. 在这个过程中我新建了一个hellospring的项目.于是乎从这个项目出发开始研究如何在maven项目中使用spring.鉴于网上的学习资 ...

  4. Docker & k8s 系列三:在k8s中部署单个服务实例

    本章将会讲解: pod的概念,以及如何向k8s中部署一个单体应用实例. 在上面的篇幅中,我们了解了docker,并制作.运行了docker镜像,然后将镜像发布至中央仓库了.然后又搭建了本机的k8s环境 ...

  5. [Laravel-Swagger]如何在 Laravel 项目中使用 Swagger

    如何在 Laravel 项目中使用 Swagger http://swagger.io/getting-started/ 安装依赖 swagger-php composer require zirco ...

  6. 如何在cocos2d项目中enable ARC

    如何在cocos2d项目中enable ARC 基本思想就是不支持ARC的代码用和支持ARC的分开,通过xcode中设置编译选项,让支持和不支持ARC的代码共存. cocos2d是ios app开发中 ...

  7. 如何在NodeJS项目中优雅的使用ES6

    如何在NodeJS项目中优雅的使用ES6 NodeJs最近的版本都开始支持ES6(ES2015)的新特性了,设置已经支持了async/await这样的更高级的特性.只是在使用的时候需要在node后面加 ...

  8. 如何在VUE项目中添加ESLint

    如何在VUE项目中添加ESLint 1. 首先在项目的根目录下 新建 .eslintrc.js文件,其配置规则可以如下:(自己小整理了一份),所有的代码如下: // https://eslint.or ...

  9. VS2015 项目中 添加windows服务

    1. 在项目中添加winows服务 今天刚刚为自己的项目添加了windows服务,以服务的形式运行后台系统,为前端提供接口服务,下面说一下具体怎么为vs项目添加windows服务 2. 添加Windo ...

随机推荐

  1. web前端学习(二)html学习笔记部分(10)-- HTML5构建应用布局和页面

    1.2.25  HTML5构建应用布局和页面 1.2.25.1  HTML5在移动开发中的准则 1.尽量使用单页面开发 2.慎重选择前端UI框架 3.动画.特效使用准则(60fps) 浏览器消耗最小的 ...

  2. web前端学习(二)html学习笔记部分(3)--range对象

    1.2.8  html5编辑api之range对象(一) 1.2.8.1  Range 对象基本概念 Range 对象的基本概念,通过使用 Range 对象所提供的方法实现一个鼠标选取内容,通过点击按 ...

  3. js中保存成图片并下载

    1.保存canvas中绘制的内容为图片 HTML代码: <canvas id="canvas" width="400" height="400& ...

  4. jquery购物评分

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  5. C++ UNREFERENCED_PARAMETER函数的作用

    新建win32 application程序,会有这样一段代码 int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hP ...

  6. js树状菜单

    html部分 <ul class="tree"> <li><span><a href="#">JavaScrip ...

  7. 【JZOJ4359】【GDKOI2016】魔卡少女

    题目描述 君君是中山大学的四年级学生.有一天在家不小心开启了放置在爸爸书房中的一本古书.于是,君君把放在书中最上面的一张牌拿出来观摩了一下,突然掀起一阵大风把书中的其她所有牌吹散到各地.这时一只看上去 ...

  8. 2017 校赛 问题 B: CZJ-Superman

    题目描述 “那是只鸟?那是飞机?那是——超人!” 程序员在看完<CZJ-Superman>之后,励志要成为一名“CZJ-Superman”,学会了两个特殊技能ZZZ和JJJ,足以成为一名“ ...

  9. IDEA切换git分支

    查看当前所在分支 场景:在多人开发中,需要在主分支的基础上创建一些分支分配给小团队或个人去开发,然后小分支上的小功能开发完毕之后,再merge(合并)到主分支. 1.查看当前所在的分支 下图1.1中是 ...

  10. Libevent:7Bufferevents基本概念

    很多时候,应用程序除了能响应事件之外,还希望能够处理一定量的数据缓存.比如,当写数据的时候,一般会经历下列步骤: l  决定向一个链接中写入一些数据:将数据放入缓冲区中: l  等待该链接变得可写: ...