前面两章分别介绍了:

JavaWeb开发(一)框架搭建(使用Maven搭建JavaWeb工程)

JavaWeb开发(二)框架搭建(给工程添加spring支持)

其中在第二章最后,我们搭建了一个有spring支持的web工程,如何验证框架搭建的是否正确呢,这里我们使用CXF技术开发一个简单的webService服务端,然后使用客户端调用一下,如果一切正常,说明我们的spring搭建没有问题,同时也学习了CXF的基本使用。闲话不多说,马上开始。

服务端开发过程

(1)首先介绍一下基础环境,我们的jdk是1.6,tomcat是7,spring使用的是spring3,cxf准备使用2.7,这里特别需要说明的是,cxf 3.0以后的版本只能在jdk1.7上使用,如果在1.6使用的话,会直接报错的。

(2)首先添加jar包支持,在pom.xml里面添加如下代码:


<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>2.7.18</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>2.7.18</version>
</dependency>

添加完成后,完整的pom文件为:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.xiaomager</groupId>
 <artifactId>test3</artifactId>
 <packaging>war</packaging>
 <version>0.0.1-SNAPSHOT</version>
 <name>test3Maven</name>
 <url>http://maven.apache.org</url>
 <dependencies>
 <dependency>
 <groupId>junit</groupId>
 <artifactId>junit</artifactId>
 <version>4.10</version>
 <scope>test</scope>
 </dependency>
 <dependency>
 <groupId>org.apache.cxf</groupId>
 <artifactId>cxf-rt-frontend-jaxws</artifactId>
 <version>2.7.18</version>
 </dependency>
 <dependency>
 <groupId>org.apache.cxf</groupId>
 <artifactId>cxf-rt-transports-http</artifactId>
 <version>2.7.18</version>
 </dependency>

 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-beans</artifactId>
 <version>3.2.2.RELEASE</version>
 </dependency>
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-web</artifactId>
 <version>3.2.2.RELEASE</version>
 </dependency>
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-core</artifactId>
 <version>3.2.2.RELEASE</version>
 </dependency>
 </dependencies>
 <build>
 <finalName>test3</finalName>
 </build>
</project>

保存后,会自动添加如下jar包到maven的本地库。

(2)添加配置文件支持

一共有三处配置文件需要更新

第一处:需要新增一个cxf的配置文件,这里取名为cxf-servlet.xml,内容如下:


<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd

http://cxf.apache.org/jaxws


http://cxf.apache.org/schemas/jaxws.xsd">

<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<context:component-scan base-package="com.xiaomager" />
<bean id="cxfdemo" class="com.xiaomager.cxf.server.impl.MyCxfServerImpl">
</bean>
<jaxws:endpoint id="cxfService" implementor="#cxfdemo"
address="/cxfserver" />
</beans>

这里面主要就是定义了一个cxfService,它的 实现类是com.xiaomager.cxf.server.impl.CxfServerImpl,这个 实现类我们在第三步骤来加上,其次还定义了一个/cxfserver的路径,即我们的cxfserver服务端的请求路径。

第二处:需要在spring主配置applicationContext文件里把这个新建的文件添加上,配置如下:


<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd


http://www.springframework.org/schema/context


http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<import resource="cxf-servlet.xml"/>
</beans>

第三处:就是需要在web.xml里面配置cxf的servlet,具体如下:


<?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_3_0.xsd" version="3.0">
<display-name>test3</display-name>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/webService/*</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

这里面主要定义了一个org.apache.cxf.transport.servlet.CXFServlet的servlet来处理  /webService/*的请求,所以 我们的cxf的全路径应该是 这里的servlet-mapping加上第一处的address,即  /webService/cxfserver

(3)添加cxf服务端的接口类和接口实现类

cxfserver

如上图所示:ImyCxfServer.java 的内容如下:


package com.xiaomager.cxf.server;

import javax.jws.WebService;

@WebService
public interface IMyCxfServer {
String sayHello(String name);
}

实现类MyCxfServerImpl的内容如下:


package com.xiaomager.cxf.server.impl;

import javax.jws.WebService;

import com.xiaomager.cxf.server.IMyCxfServer;

@WebService
public class MyCxfServerImpl implements IMyCxfServer {

@Override
public String sayHello(String name) {
// TODO Auto-generated method stub
return "hello "+name;
}

}

以上代码表示的意思很明白,即服务端提供一个sayHello的方法,将客户端传递的字符串参数 前面加上 hello 后返回。

(4)maven clean 然后maven install一下,如果觉得不方便可以一次性完成,即右键工程,run as,选择最后的那个run configurations,如图配置一下 goals为clean,install,然后直接run即可。

runconfig

(5)在tomcat里面部署工程,启动tomcat,如图:

deploy

(6)在浏览器里,访问一下这个cxf地址:http://ip:port/工程名/webService/cxfserver?wsdl,我本机的实际访问地址是:http://localhost:7080/xiaomager/webService/cxfserver?wsdl  如图:

wsdl

 

从上图中,最后一个标红的地方可以看出我们的地址为:http://localhost:7080/xiaomager/webService/cxfserver,并且上面的operation即方法名是sayHello,而第一个标红的是import了一个wsdl,即参数类型,我们打开这个wsdl:

type

从上图中也可以看出,sayHello方法的入参是String类型,返回值也是String类型。

客户端开发

(7)完成上面的6个步骤即完成了服务端的开发,下面说一下客户端的开发,客户端的开发分为以下几种

  1. 自己本地直接调用,不需要下载webService 服务端代码,直接拷贝使用即可,这个比较适合本机测试。
  2. 动态客户端调用,即只需要知道webService地址和方法名即可,每次动态调用,由于不是远程下载webService的服务端代码,所以这种方式速度较下载服务端代码作为本地代码使用的方式慢一些,不过它也有它的优点,即开发简单,而且动态调用,如果服务端代码经常变化,每次如果下载的话太过于负载,动态调用就比较适合,另外如果webService服务端较多,客户端是一个需要连接多个服务端地址的程序,动态调用较为方便,因为不用下载很多服务端代码。
  3. 如果webService的服务端是别人开发的,我们手里没有源代码,则需要使用wsdl工具(jdk也有自带的)下载远程的代码,然后将下载的代码作为本机代码,使用cxf的客户端调用程序 即可,这种方式比较适用于和外部程序联调,而且服务端程序变化较小。

这里的本文介绍客户端开发使用上面提到的第1种方法,这个较为简单,第二种动态调用和第三种wsdl下载使用在后续的文章会继续介绍。

(8)首先如图:新建一个客户端java文件,这里名为CxfClient1:

CxfClient1

 

该类的内容如下:


package com.xiaomager.cxf.client;

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;

import com.xiaomager.cxf.server.IMyCxfServer;

public class CxfClient1 {

public static void main(String[] args) {
 JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
 factory.setServiceClass(IMyCxfServer.class);
 String url = "http://localhost:7080/xiaomager/webService/cxfserver";
 factory.setAddress(url);
 IMyCxfServer service = (IMyCxfServer) factory.create();
 Client proxy = ClientProxy.getClient(service);
 HTTPConduit conduit = (HTTPConduit) proxy.getConduit();
 HTTPClientPolicy policy = new HTTPClientPolicy();
 policy.setConnectionTimeout(120000); // 连接超时时间
 policy.setReceiveTimeout(120000);// 请求超时时间
 conduit.setClient(policy);

 String name = "tom";
 String he = service.sayHello(name);
 System.out.println(he);
 }

}

注意这里的url是不带用?wsdl的后缀的。直接运行一下这个main方法即可,如图:

result

这里标红的内容如下:

2016-7-31 20:22:12 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromClass
信息: Creating Service {http://server.cxf.xiaomager.com/}IMyCxfServerService from class com.xiaomager.cxf.server.IMyCxfServer
hello tom

从这里的信息可以看出,在创建Service。

复杂对象传递

(9)上面的例子我们已经完成了一个简单的CXF服务端和客户端开发的小例子,我们的CXF服务传递的是基本数据类型String,如果是复杂的对象呢,实际上是一样的,我们这里来试一下,首先如图建立实体对象类,Student类,这个类继承Person类,

domain

 

Person类内容如下:


package com.xiaomager.cxf.domain;

public class Person {
 private String name;
 private int age;
 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }
 public int getAge() {
 return age;
 }
 public void setAge(int age) {
 this.age = age;
 }

}

Student类内容如下:


package com.xiaomager.cxf.domain;

public class Student extends Person {
 private String number;
 private double score;
 public String getNumber() {
 return number;
 }
 public void setNumber(String number) {
 this.number = number;
 }
 public double getScore() {
 return score;
 }
 public void setScore(double score) {
 this.score = score;
 }
 public String toString(){
 return super.getName()+","+super.getAge()+","+number+","+score;
 }
}

内容很简单,Person有姓名和年龄两个属性,Student有学号和分数两个属性。

(10)在接口里添加一个加分的方法同时完成它的实现类

我们的接口IMyCxfServer.java代码变成了这样:


package com.xiaomager.cxf.server;

import javax.jws.WebService;

import com.xiaomager.cxf.domain.Student;

@WebService
public interface IMyCxfServer {
 String sayHello(String name);
 Student addScore(Student stu,double score);
}

实现类的代码如下:


package com.xiaomager.cxf.server.impl;

import javax.jws.WebService;

import com.xiaomager.cxf.domain.Student;
import com.xiaomager.cxf.server.IMyCxfServer;

@WebService
public class MyCxfServerImpl implements IMyCxfServer {

@Override
 public String sayHello(String name) {
 // TODO Auto-generated method stub
 return "hello "+name;
 }

@Override
 public Student addScore(Student stu, double score) {
 // TODO Auto-generated method stub
 if(stu == null){
 stu = new Student();
 }
 stu.setScore(stu.getScore()+score);
 return stu;
 }

}

从以上代码中,可以知道,我们先添加了一个方法addScore,接收两个参数,第一个是复杂对象Student,第二个是double类型的参数score,实现的目标就是把score和Student原有的得分相加赋值给Student并返回。

(11)我们服务端的新加功能已经开发完成,重新部署一下tomcat,启动看看喽

我们的主服务地址:http://localhost:7080/xiaomager/webService/cxfserver?wsdl,截图如下:

addScore

可以看出已经多了addScore这个方法,来看import里面的参数类型的信息,地址如下:

http://localhost:7080/xiaomager/webService/cxfserver?wsdl=IMyCxfServer.wsdl

addScoretype

从这里也能明显的看出Student和Person的关系,由于这个参数类型的配置文件过大,截图不便,我这里作为xml内容粘贴如下:


<?xml version='1.0' encoding='UTF-8'?><wsdl:definitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:ns1="http://server.cxf.xiaomager.com/" name="IMyCxfServer" targetNamespace="http://server.cxf.xiaomager.com/">
 <wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://server.cxf.xiaomager.com/" elementFormDefault="unqualified" targetNamespace="http://server.cxf.xiaomager.com/" version="1.0">

 <xs:element name="addScore" type="tns:addScore"/>

 <xs:element name="addScoreResponse" type="tns:addScoreResponse"/>

 <xs:element name="sayHello" type="tns:sayHello"/>

 <xs:element name="sayHelloResponse" type="tns:sayHelloResponse"/>

 <xs:complexType name="addScore">
 <xs:sequence>
 <xs:element minOccurs="0" name="arg0" type="tns:student"/>
 <xs:element name="arg1" type="xs:double"/>
 </xs:sequence>
 </xs:complexType>

 <xs:complexType name="student">
 <xs:complexContent>
 <xs:extension base="tns:person">
 <xs:sequence>
 <xs:element minOccurs="0" name="number" type="xs:string"/>
 <xs:element name="score" type="xs:double"/>
 </xs:sequence>
 </xs:extension>
 </xs:complexContent>
 </xs:complexType>

 <xs:complexType name="person">
 <xs:sequence>
 <xs:element name="age" type="xs:int"/>
 <xs:element minOccurs="0" name="name" type="xs:string"/>
 </xs:sequence>
 </xs:complexType>

 <xs:complexType name="addScoreResponse">
 <xs:sequence>
 <xs:element minOccurs="0" name="return" type="tns:student"/>
 </xs:sequence>
 </xs:complexType>

 <xs:complexType name="sayHello">
 <xs:sequence>
 <xs:element minOccurs="0" name="arg0" type="xs:string"/>
 </xs:sequence>
 </xs:complexType>

 <xs:complexType name="sayHelloResponse">
 <xs:sequence>
 <xs:element minOccurs="0" name="return" type="xs:string"/>
 </xs:sequence>
 </xs:complexType>

</xs:schema>
 </wsdl:types>
 <wsdl:message name="sayHelloResponse">
 <wsdl:part element="ns1:sayHelloResponse" name="parameters">
 </wsdl:part>
 </wsdl:message>
 <wsdl:message name="sayHello">
 <wsdl:part element="ns1:sayHello" name="parameters">
 </wsdl:part>
 </wsdl:message>
 <wsdl:message name="addScore">
 <wsdl:part element="ns1:addScore" name="parameters">
 </wsdl:part>
 </wsdl:message>
 <wsdl:message name="addScoreResponse">
 <wsdl:part element="ns1:addScoreResponse" name="parameters">
 </wsdl:part>
 </wsdl:message>
 <wsdl:portType name="IMyCxfServer">
 <wsdl:operation name="addScore">
 <wsdl:input message="ns1:addScore" name="addScore">
 </wsdl:input>
 <wsdl:output message="ns1:addScoreResponse" name="addScoreResponse">
 </wsdl:output>
 </wsdl:operation>
 <wsdl:operation name="sayHello">
 <wsdl:input message="ns1:sayHello" name="sayHello">
 </wsdl:input>
 <wsdl:output message="ns1:sayHelloResponse" name="sayHelloResponse">
 </wsdl:output>
 </wsdl:operation>
 </wsdl:portType>
</wsdl:definitions>

(12)修改一下客户端CxfClient1的代码,添加上对于addScore 方法的调用,如下:

package com.xiaomager.cxf.client;

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;

import com.xiaomager.cxf.domain.Student;
import com.xiaomager.cxf.server.IMyCxfServer;

public class CxfClient1 {

 public static void main(String[] args) {
 JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
 factory.setServiceClass(IMyCxfServer.class);
 String url = "http://localhost:7080/xiaomager/webService/cxfserver";
 factory.setAddress(url);
 IMyCxfServer service = (IMyCxfServer) factory.create();
 Client proxy = ClientProxy.getClient(service);
 HTTPConduit conduit = (HTTPConduit) proxy.getConduit();
 HTTPClientPolicy policy = new HTTPClientPolicy();
 policy.setConnectionTimeout(120000); // 连接超时时间
 policy.setReceiveTimeout(120000);// 请求超时时间
 conduit.setClient(policy);

 String name = "tom";
 String he = service.sayHello(name);
 System.out.println(he);

 Student stu = new Student();
 stu.setName("tom");
 stu.setAge(20);
 stu.setNumber("111111");
 stu.setScore(45.5);
 stu = service.addScore(stu, 30);
 System.out.println(stu);
 }

}

运行一下,结果如图:

resultaddScore

运行结果表明加分成功。

 

总结

本文主要介绍了在Spring框架的支持下,利用CXF框架来实现WebService服务端和客户端的开发,实现了简单String参数和复杂对象的参数传递。其中文章里没有涉及到的另外两种客户端调用方式(动态调用和wsdl下载 )会在后续的文章中介绍。

 

 

 

 

 

tomcat参数详解与性能优化

其实,前面有些文章已经涉及到相关的内容了,比如: 快速学会Linux安装jdk和tomcat tomcat部署应用的三种方法 本文会详细介绍一下在tomcat安装完成之后一般...

阅读全文

tomcat部署应用的三种方法

在JavaWeb的开发中,tomcat是最常用的web容器,使用tomcat部署web应用,常见的有三种方式,下面以我们在前面开发过的一个WebService的服务端为例(具体服务开...

阅读全文

JavaWeb开发(四)CXF webService 客户端开发(动态调用与wsdl2java生成)

前面三章分别介绍了: JavaWeb开发(一)框架搭建(使用Maven搭建JavaWeb工程) JavaWeb开发(二)框架搭建(给工程添加spring支持) JavaWeb开发(三)CXF ...

阅读全文

欢迎留言