Spring5.x+CXF3.x+Tomcat构建SOAP服务
JDK自带类库支持发布SOAP服务,开发比较简单,但是不方便管理和扩展.CXF对ws和rs类的WebService有良好的支持,并且可以无缝与Sping集成,使得开发过程非常简单,且便于扩展。
一、使用JDK原生的类库开发SOAP服务
1、创建java项目(不需要是Web项目,用main方法启动)
2、创建接口类
百度搜到最多的就是sayHello,这里的注解可以不用加,形参里面的注解能够修改WSDL文件中参数的名字
package test;
import javax.jws.WebService;
import javax.jws.WebParam;
@WebService
public interface ICxfTest {
public String say(@WebParam(name="hello")String str);
public String powerOfTwo(int n);
}
3、创建实现类
这里实现了接口中的2个方法,say()返回一段写死的字符串加上客户端传输的字符串。powerOfTwo()返回2的幂,能够计算一个较大的值,比如2的1000次方,通过模拟手算乘法的进位,以字符串返回结果来实现。
package test;
import javax.jws.WebParam;
import javax.jws.WebService;
@WebService
public class CxfTest implements ICxfTest{
public String say(@WebParam(name="hello")String str)
{
return "原生jdk实现CXF" +str;
}
public String powerOfTwo(int n)
{
String result = powerOfNumber(2,n);
return result;
}
public static String powerOfNumber(int baseNumber, int n)
{
if(baseNumber>9||baseNumber<0) return null;
String result = "";
int a[];
a = new int[n];
int i,j;
for(i=0;i<n;i++)
{
a[i]=0;
}
a[0]=1;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
a[j]*=baseNumber;
}
for(j=0;j<n;j++)
{
if(a[j]>9)
{
a[j+1]+=a[j]/10;
a[j]=a[j]%10;
}
}
}
int k = n-1;
for(;k>=0;k--)
{
if(a[k]!=0)break;
}
for(i=k;i>=0;i--)
{
result +=a[i];
}
return result;
}
}
4、创建发布类
这里使用了JDK自带的EndPoint类发布服务,没有借助任何第三方框架,通过main方法来启动,一旦启动,可以持续访问。这一步完成后将服务的发布地址copy到浏览器或SoapUI就可以看到WSDL文件了,通过SoapUI传递入参还可以收到返回。但是这里把服务地址写死了,只能这个地址,本人尝试过在访问时用ipconfig得到的IP替换localhost,结果是拒绝连接,如果想发布给其他人使用,可以将localhost换成IP,这样在局域网内其他人就可以访问了,端口不一定非要是8080,只要是没有被占用的端口都可以,至此,服务端已经开发完毕了。
package test;
import javax.xml.ws.Endpoint;
public class PublishServiceTest {
public static void main(String[] args)
{
System.out.println("服务开始启动");
ICxfTest cxfTest = new CxfTest();
String address = "http://localhost:8080/test";
//使用Endpoint类提供的publish方法发布WebService,发布时要保证使用的端口号没有被其他应用程序占用
Endpoint.publish(address, cxfTest);
System.out.println("服务已启动");
}
}
5、创建客户端
创建客户端就更简单了,可以通过CMD的命令生成,如
//通过wsdl按指定名称输出package:
wsimport -s ./ -p com.skd.client.wsimport http://localhost:8080/test?wsdl
会在指定地方生成一些类,如下是我输入命令后生成的一些文件,那时候求2的次方函数名字还是叫squareOfTwo()
如下是我创建的客户端Java项目,只导入了生成的部分java文件,并把CxfTest.java中的一点内容删掉了,即注释部分,因为我没有引入那个类,不删除会报错,这个参考了https://blog.****.net/lovecarpenter/article/details/53946108第4节的做法,较为简单。
如下是调用的类,这里的访问地址最好与你的发布地址一致,启动main方法后即可获得你传参对应的返回。
package wsimportTest;
import java.net.URL;
import java.net.MalformedURLException;
import javax.xml.ws.Service;
import javax.xml.namespace.QName;
public class Test {
public static void main(String[] args) throws MalformedURLException
{
String wsUrl = "http://127.0.0.1:8080/test?wsdl";
//QName的第一个参数是服务的命名空间,第二个参数是服务的名称
Service service = Service.create(new URL(wsUrl), new QName("http://test/","CxfTestService"));
//QName的第一个参数是服务的命名空间,第二个参数是得到接口的Port
CxfTest port = service.getPort(new QName("http://test/","CxfTestPort"),CxfTest.class);
String ret = port.say("CXF 客户端测试");
String result = port.squareOfTwo(1000);
System.out.println(ret);
System.out.println(result);
}
除了使用wsimport命令生成客户端外,还可以通过Eclipse的创建客户端项目生成,也可以使用SoapUI来生成,当然,可以直接使用HttpURLConnection构造SOAP消息来调用。
二、使用Spring5.0.0+CXF3.2.5构建SOAP服务
我下载的时候Spring已经更新到5.0.7(http://repo.springsource.org/libs-release-local/org/springframework/spring/),CXF更新到3.2.5(http://cxf.apache.org/download.html)。在学习搭建的时候在百度上还没有找到Spring5.x的内容,主要集中在使用maven引入jar包,但即便是根据各种帖子的引入包来搭建,我仍然遇到了很多很多的问题。如下是我引入的jar包,在实践中发现缺一不可,而不是很多帖子的spring2个包,CXF2个包。比如commons-logging是使用spring必须引入的包,具体的缺包提示可参考:https://blog.****.net/w1014074794/article/details/47862163,非常全。这些包最好放在lib目录下,本人尝试过在lib目录下分别创建2个文件夹,放入各自的包并手动引入,遇到很多问题。
1、创建Web项目,引入Spring和CXF的包,并在web.xml配置spring的监听和CXF的Servlet,如下:
<listener>
<description>SpringListener</description>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring.xml</param-value>
</context-param>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/ws/*</url-pattern>
</servlet-mapping>
2、创建接口
package com.weijie.service.api;
import javax.jws.WebService;
@WebService
public interface IExcelExport {
String invokeTask(String appID);
String searchTaskStatus(String guid,String appID);
public String powerOfTwo(int n);
public String say(String str);
}
3、实现接口
package com.weijie.service.impl;
import com.weijie.service.api.IExcelExport;
import com.weijie.util.Sequence;
import javax.jws.WebService;
@WebService(serviceName = "IExcelExport",
endpointInterface = "com.weijie.service.api.IExcelExport")
public class ExcelExport implements IExcelExport {
public String invokeTask(String appID)
{
//String guid = null;
return Sequence.generateSequence();
}
public String searchTaskStatus(String guid,String appID)
{
String status = "";
return status;
}
public String powerOfTwo(int n)
{
return powerOfNumber(2,n);
}
public static String powerOfNumber(int baseNumber, int n)
{
if(baseNumber>9||baseNumber<0) return null;
String result = "";
int a[];
a = new int[n];
int i,j;
for(i=0;i<n;i++)
{
a[i]=0;
}
a[0]=1;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
a[j]*=baseNumber;
}
for(j=0;j<n;j++)
{
if(a[j]>9)
{
a[j+1]+=a[j]/10;
a[j]=a[j]%10;
}
}
}
int k = n-1;
for(;k>=0;k--)
{
if(a[k]!=0)break;
}
for(i=k;i>=0;i--)
{
result +=a[i];
}
return result;
}
public String say(String str)
{
return "你好,这里是我第一个用CXF框架构建的SOAP服务,欢迎使用!" +str;
}
}
4、Spring的配置文件
这里的jaxws:endpoint标签即是发布服务,配置了bean,并指出了实现类和发布地址(此处并没有指定IP和端口,使用了Tomcat部署,默认8080端口)
<?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: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://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<!-- <bean id="IExcelExportBean" class="com.weijie.service.impl.ExcelExport"></bean>
-->
<jaxws:endpoint id="IExcelExport" implementor="com.weijie.service.impl.ExcelExport" address="/IExcelExport">
</jaxws:endpoint>
</beans>
这里的<jaxws:endpoint……>方式相当于前面使用原生JDK的方式发布SOAP服务,相当于:
Endpoint.publish("http://localhost:8080/IExcelExport", new ExcelExport());
还可以使用<jaxws:server serviceClass="com.weijie.service.impl.ExcelExport" address="/IExcelExport">,相当于:
JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
这是cxf-rt-frontend-jaxws包下的类,通过继承依赖一些CXF其它的包,事实上,不依赖Spring,CXF也能构建SOAP服务,只是不方便修改和扩展。
在百度搜到的很多帖子都有在spring的配置文件里配置引入CXF的配置文件,有少数贴说这个已经不用了,经实践,已经不需要了,至此,通过Spring+CXF+Tomcat构建SOAP服务已经完成,可通过SoapUI测试
访问地址格式:http://IP:port/项目名/CXF拦截器拦截的地址/服务发布地址?wsdl