分享

Spring-ws示例WebService开发

 江江385 2013-01-21

概述

我们这里要编写一个WebService的Endpoint,它可以接收一个UserRequest对象,这个对象当中只包含一个userCount的参数,Endpoint接收到参数后,会产生与userCount相同数量的User对象,最后将这个User对象的集合放在一个名为UserResponse的对象当中作为Endpoint的调用响应发送给调用这个WebService的客户端。接下来我们先从编写WebService服务端开始,看看如何实现这个WebService示例。

WebService服务端开发

因为在我们的WebService服务端当中引入了JAXB2,所以整个服务端Endpoint类编写变的简单,同时Spring-WS2.0支持将XSD文档自动转换成WSDL,这样我们就不用直接编写复杂的WSDL,而只需要编写好XSD文档即可实现WSDL发布。一般来说,一个WebService的编写是从定义WSDL开始的,对于我们这里来说,因为我们可以将XSD自动转换成WSDL,所以我们就是从编写简单的XSD开始。

关于XSD文档的语法规范,如果您不熟悉,可以从http://www.w3school.com.cn/schema/index.asp上面了解。

我们这里规定,所有的进站参数在定义XSD时要以Request结尾,比如我们这里的UserRequest;所有的出站参数要以Response结尾,比如我们这里的UserResponse。了解这些之后就可以定义们的XSD文档,具体内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://www./ws/demo" elementFormDefault="qualified" xmlns="http://www./2001/XMLSchema" xmlns:tns="http://www./ws/demo">
<element name="UserResponse">
<complexType>
<sequence>
<element name="users" type="tns:User" maxOccurs="unbounded"></element>
</sequence>
</complexType>
</element>
<element name="UserRequest">
<complexType>
<all>
<element name="userCount" type="int"></element>
</all>
</complexType>
</element>
<complexType name="User">
<sequence>
<element name="username" type="string"></element>
<element name="birthday" type="date"></element>
<element name="gender" type="boolean"></element>
<element name="email" type="string"></element>
<element name="dept" type="tns:Dept"></element>
</sequence>
</complexType>
<complexType name="Dept">
<sequence>
<element name="deptId" type="string"></element>
<element name="deptName" type="string"></element>
</sequence>
</complexType>
</schema>

XSD文档的编写是非常简单的,如果您使用的IDE是Eclipse,那么您可以直接使用Eclipse当中提供了XSD图形化编辑器来编写这个XSD文档。从文档内容中可以看到,我们定义消息的namespace为http://www./ws/demo,同时定义了一个名为UserRequest的Element为进站参数;一个名为UserResponse的Element为出站参数。
XSD文档编写完成之后,我们就可以利用Spring-WS提供的配置功能将XSD直接转换成我们需要的WSDL。

因为我们采用的是Spring-WS为基础实现WebService,所以一旦XSD文档编写完成我们就可以通过配置的方式将XSD转换成WSDL,新建一个Spring配置文件,在文件当中添加如下内容:

<?xml version="1.0" encoding="UTF-8"?>
xsi:schemaLocation="http://www./schema/beans http://www./schema/beans/spring-beans-3.0.xsd
http://www./schema/context >
<context:component-scan base-package="com.bstek.bdf.webservice.demo"></context:component-scan>
<sws:dynamic-wsdl id="demo" portTypeName="UserResource" locationUri="/webservice/demo">
<sws:xsd location="classpath:com/bstek/bdf/webservice/demo/demo.xsd" />
</sws:dynamic-wsdl>
</beans>

我们需要关注的就是这个配置文件当中以sws:dynamic-wsdl开头的配置片断,这里采用位于classpath下的一个xsd文档,发布成WSDL的ID为demo,同时客户端调用这个WebService的地址我们定义为/webservice/demo。启用我们的应用,打开浏览器,可以浏览到这个动态生成的名为demo的wsdl文档。如下图所示。

WSDL发布成功之后,接下来我们就需要动手来编写我们的WebService服务端的Endpoint,由这个EndPoint来接收客户端的调用请求。
Endpoint实际上是WebService真正的服务类,我们只需要按照之前发布的WSDL规则来编写即可,由它来接收客户端请求,同时将响应回写到客户端当中。因为Spring提供了Endpoint的annotation,同时我们又添加了JAXB2支持,所以Endpoint类编写是非常简单的。下面是我们编写的与之前发布的WSDL对应的Endpoint类源码:

package com.bstek.bdf.webservice.demo;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
@Endpoint
public class UserServiceEndpoint{
@PayloadRoot(namespace=" http://www./ws/demo",localPart="UserRequest")
@ResponsePayload
public UserResponse findUsers(@RequestPayload UserRequest request) throws Exception{
List<User> userList=new ArrayList<User>();
for(int i=0;i<request.getUserCount();i++){
User u=new User();
u.setBirthday(new Date());
u.setGender(true);
u.setUsername("从WS中取到的User "+i);
u.setEmail("bstek.user"+i+".");
userList.add(u);
}
for(int i=0;i<100;i++){
Thread.sleep(50);
}
UserResponse res=new UserResponse();
res.setUsers(userList);
return res;
}
}

可以看到,我们这里采用了四个annotation,在类上的@Endpoint标明我们将这个类发布成一个Endpoint服务类,findUsers方法上有两个annotation:@PayloadRoot用于标明findUser可以授受的XML信息,这里取的是XML的namespace为http://www./ws/demo,同时XML的ROOT为UserRequest的信息;下面的@ResponsePayload标明findUsers方法有返回值,返回值需要回写给Webservice调用客户端;参数中还有一个@RequestPayload的annotation,它表示从请求负载中取值作为参数,我们这里因为采用了JAXB2,所以可以将负载的XML消息直接转换成一个名为UserRequest的Java对象。
从findUsers方法体中可以看到,其中都是针对Java对象的操作,是非常简单的。这是因为我们添加了JAXB2支持的原因,如果没有我们这里就只能操作复杂的XML了。
我们这里涉及到的需要使用JAXB2实现Java对象与XML相互转换的类有下面几个:

  • UserRequest
    package com.bstek.bdf.webservice.demo;
    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlRootElement;
    @XmlRootElement(namespace="http://www./ws/demo",name="UserRequest")
    @XmlAccessorType(XmlAccessType.FIELD)
    public class UserRequest {
    private int userCount;
    public int getUserCount() {
    return userCount;
    }
    public void setUserCount(int userCount) {
    this.userCount = userCount;
    }
    }
    UserResponse
    package com.bstek.bdf.webservice.demo;
    import java.util.List;
    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlRootElement;
    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    public class UserResponse {
    private List<User> users;
    public List<User> getUsers() {
    return users;
    }
    public void setUsers(List<User> users) {
    this.users = users;
    }
    }

User

package com.bstek.bdf.webservice.demo;
import java.util.Date;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="User",namespace="http://www./ws/demo")
@XmlAccessorType(XmlAccessType.FIELD)
public class User {
private String username;
private Date birthday;
private boolean gender;
private String email;
private Dept dept;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public boolean isGender() {
return gender;
}
public void setGender(boolean gender) {
this.gender = gender;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "User [username=" + username + ", birthday=" + birthday
+ ", gender=" + gender + ", email=" + email + ", dept=" + dept
+ "]";
}
}

可以看到,这三个类都是非常普通的POJO对象,它们都用到了@XmlRootElement、@XmlAccessorType,这两个annotation都是JAXB2提供,要了解详情请查看JAXB2相关文档。
到这里为止,我们的Endpoint编写就完成了,因为我们使用了Spring-WS提供的Endpoint的annotation,所以不需要在Spring配置当中进行任何配置,唯一需要的就是添加一个context:component-seca即可,这样Spring会自动扫描位于base-package属性指定包下所有的Endpoint类。
可以看到,这三个类都是非常普通的POJO对象,它们都用到了@XmlRootElement、@XmlAccessorType,这两个annotation都是JAXB2提供,要了解详情请查看JAXB2相关文档。

到这里为止,我们的Endpoint编写就完成了,因为我们使用了Spring-WS提供的Endpoint的annotation,所以不需要在Spring配置当中进行任何配置,唯一需要的就是添加一个context:component-seca即可,这样Spring会自动扫描位于base-package属性指定包下所有的Endpoint类。

<context:component-scan base-package="com.bstek.bdf.webservice.demo"></context:component-scan>

WebService的服务端我们开发完成,接下来我们就来看看客户端如何对这个服务端进行调用。

WebService客户端调用

前面提到过,我们为了实现快速调用目标WebService服务端,我们提供了一个名为WebServiceClient对象,通过它可以快速实现调用目标WebService服务端;当然你也可以使用诸如SOAPUI之类客户端工具实现对目标WebService调用测试。

我们这里以之前编写的服务端为类,看看WebServiceClient对象如何调用这个WebService。具体代码如下:

package com.bstek.bdf.webservice.demo;
import com.bstek.bdf.webservice.client.WebServiceClient;
public class DemoWebserviceClient {
public static void main(String[] args) throws Exception{
WebServiceClient client=new WebServiceClient();
//设置目标webservice地址,这个可以在WSDL文档当中看到
//设置服务验证方式,我们这里采用Username Token用户密码加密方式 ,默认我们的服务端要求用户名与密码相同即可通过认证
client.setUsernameToken("admin", "admin", true);
//添加JAXB2支持
client.setMarshallerUnmarshallerClass(new Class[]{User.class,UserResponse.class,UserRequest.class});
UserRequest request=new UserRequest();
request.setUserCount(20);
//向目标WebService发送请求,并将响应结果通过JAXB2转换成Java对象
UserResponse response=(UserResponse)client.marshalSendAndReceive(request);
int i=1;
for(User user:response.getUsers()){
//打印响应结果
System.out.println("webservice 产生的用户"+i+":"+user);
i++;
}
}
}

我们已在代码当中进行了注释,这里就不再解释。一旦调用完成(不管是成功还是失败),我们可以在bdf_webservice_logs表中看到日志记录情况。同时在默认情况下我们没有启用权限功能,所以所有用户名密码相同的用户都可以进行调用。

关于WebServiceClient类还有一个方法, 详情可查看WebServiceClient的javadoc。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多