采用JAX-WS Annotated Services from Java+JAXB发布获取web service

来源:互联网 发布:乐视mac版 下载 编辑:程序博客网 时间:2024/05/21 09:19
 

采用JAX-WS Annotated Services from Java+JAXB发布获取web service

 

CXF有多种数据绑定方式,如:Aegis  Databinding,JAXB,MTOM Attachments . 其中JAXB(JavaTM Architecture for XML Binding)是其默认的数据绑定方式。JAXB是一套自动映射XMLJava实例的开发接口和工具。

如果web Service发布的接口为:

  String sayUserHello(User user); 

List<User> findUsers();

且传入参数类型是类,而且返回的为List ,String 等,这样,发布web service与普通java的没有区别,是因为JAXB都能支持。

JAXB不能将一些 Java 类型自然映射到 XML 表示形式,例如,HashMap 或其他非 JavaBean 类。如参数类型为接口,以及Map  ,这需要特殊的XmlAdapter类进行处理. 例如:

1、    编写要发布的web service 接口和实现

import javax.jws.WebService;

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

 

@WebService

public interface HelloWorld {

    String sayHello(String text);

    String sayUserHello(User user);

    List<User> findUsers();

    @XmlJavaTypeAdapter(UserMapAdapter.class)

    Map<Integer, User> getMapUsers();

}

import java.util.ArrayList;

import java.util.LinkedHashMap;

import java.util.List;

import java.util.Map;

import javax.jws.WebService;

@WebService(endpointInterface = "test.HelloWorld",

            serviceName = "HelloWorld")

public class HelloWorldImpl implements HelloWorld {

     public String sayHello(String text) {

          return "Hello " + text;

      }

      public String sayUserHello(User user) {

         return "Hello " + (user!=null?user.getUsername():"guest");

     }

      public List<User> findUsers() {

      ArrayList<User> list = new ArrayList<User>();

      list.add(new UserImpl("aa","bb"));

      list.add(new UserImpl("aa1","bb"));

      list.add(new UserImpl("aa2","bb"));

      list.add(new UserImpl("aa3","bb"));

      return list;

     }

    public  Map<Integer,User>  getMapUsers() {

       Map<Integer, User> users = new LinkedHashMap<Integer, User>();

       users.put(1, new UserImpl("aa","bb"));

       users.put(2, new UserImpl("sss","sss"));

       return users;

  }

}

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

 

@XmlJavaTypeAdapter(UserAdapter.class)

public interface User {

    String getPassword();

    String getUsername();

    void setUsername(String username);

    void setPassword(String password);

    void setUserId(Integer userId);

    Integer getUserId();

}

@XmlType(name = "User")

public class UserImpl implements User {

    private Integer userId;

    private String username;

    private String password;

       public Integer getUserId() {

       return userId;

    }

    public void setUserId(Integer userId) {

       this.userId = userId;

    }

    public String getPassword() {

       return password;

    }

    public void setPassword(String password) {

       this.password = password;

    }

    public String getUsername() {

       return username;

    }

    public void setUsername(String username) {

       this.username = username;

    }

    public UserImpl(String username, String password) {

       super();

       this.username = username;

       this.password = password;

    }

    public UserImpl() {

    }

    public UserImpl(String username) {

       this.username = username;

    }

    public UserImpl(Integer userId, String username, String password) {

       this.userId = userId;

       this.username = username;

       this.password = password;

    }

  

}

2、    编写适配器

因为JAXB不支持将HashMap 或其他非 JavaBean 自然映射到xml表示形式,这样就要定义一个适配器使用java类型适应自定义编组.一般有两步:

1>. 编写一个类继承XmlAdapter,以实现此抽象类的适配器。

2>. 安装使用注释 XmlJavaTypeAdapter 的适配器。

 

XmlAdapter的说明:

XmlAdapter<ValueType,BoundType>

BoundType - JAXB 不知道如何处理的一些类型。编写一个适配器,以便允许通过 ValueType 将此类型用作内存表示形式。

ValueType - JAXB 无需其他操作便知道如何处理的类型。

其两个抽象方法:

marshal(...):编组过程中,JAXB 绑定框架调用 XmlAdapter.marshal(..) bound 类型修改为 value 类型,然后将 value 类型编组为 XML 表示形式。

unmarshal(...):解组过程中,JAXB 绑定框架首先将 XML 表示形式解组为 value 类型,然后调用 XmlAdapter.unmarshal(..) value 类型修改为 bound 类型。

 

常用的几个注释说明:

a.@XmlJavaTypeAdapter 注释可以与下列编程元素一起使用: JavaBean 属性 、字段、参数 、包 XmlJavaTypeAdapters 内部的元素 。用来表示使用实现 XmlAdapter 的适配器,告诉其如何如何转换。

b. @XmlType 注释可以与以下程序元素一起使用:顶层类、枚举类型 。表示将类或枚举类型映射到 XML 模式类型。

c. @XmlAccessorType 注释可以与以下程序元素一起使用:包、顶层类。表示控制默认情况下是否对字段或 Javabean 属性进行序列化。

@XmlAccessorType(XmlAccessType.FIELD)

FIELD JAXB 绑定类中的每个非静态、非瞬态字段将会自动绑定到 XML,除非由 XmlTransient 注释。

d. @XmlElement 注释可以与以下程序元素一起使用: JavaBean 属性、非 static、非 transient 字段 XmlElements 中的程序元素 。表示 JavaBean 属性映射到派生于属性名称的 XML 元素。

如:将User接口转化的适配器类:UserAdapter:

import javax.xml.bind.annotation.adapters.XmlAdapter;

 

/*XmlAdapter<ValueType,BoundType>

 * BoundType - JAXB 不知道如何处理的一些类型。编写一个适配器以便允许通过 ValueType 将此类型用作内存表示形式。

ValueType - JAXB 无需其他操作便知道如何处理的类型。

*/

public class UserAdapter extends XmlAdapter<UserImpl, User> {

   /*marshal表示要将user类型编组为UserImpl类型*/

    public UserImpl marshal(User v) throws Exception {

        if (v instanceof UserImpl) {

            return (UserImpl)v;

        }

        return new UserImpl(v.getUsername(),v.getPassword());

    }

    /*marshal表示要将UserImpl类型解组为具体的类User*/

    public User unmarshal(UserImpl v) throws Exception {

        return v;

    }

}

 

Map转化的适配器类:UserMapAdapter.java  UserMap.java

@XmlType(name = "UserMap")

@XmlAccessorType(XmlAccessType.FIELD)

public class UserMap {

     @XmlElement(nillable = false, name = "entry")

     List<UserEntry> entries = new ArrayList<UserEntry>();

 

    /**

     * @return the entries

     */

    public List<UserEntry> getEntries() {

       return entries;

    }

     @XmlAccessorType(XmlAccessType.FIELD)

     @XmlType(name = "IdentifiedUser")

     static class UserEntry {

            //Map keys cannot be null

            @XmlElement(required = true, nillable = false)

            Integer id;

            User user;

            public void setId(Integer k) {

                id = k;

            }

            public Integer getId() {

                return id;

            }

            public void setUser(User u) {

                user = u;

            }

            public User getUser() {

                return user;

            }

        }

}

public class UserMapAdapter extends XmlAdapter<UserMap,Map<Integer,User>> {

    @Override

    public UserMap marshal(Map<Integer, User> v) throws Exception {

       UserMap  userMap=new UserMap();

        for (Map.Entry<Integer, User> e : v.entrySet()) {     

               UserMap.UserEntry iue = new UserMap.UserEntry();

                iue.setUser(e.getValue());

                iue.setId(e.getKey());

                userMap.getEntries().add(iue);

            }

            return userMap;

    }

    @Override

    public Map<Integer, User> unmarshal(UserMap v) throws Exception {

         Map<Integer, User> map = new LinkedHashMap<Integer, User>();

            for (UserMap.UserEntry e : v.getEntries()) {

                map.put(e.getId(), e.getUser());

            }

            return map;

    }

}

3、    发布web service

public class Server {

    protected Server() throws Exception {

         System.out.println("Starting Server");

         HelloWorldImpl implementor = new HelloWorldImpl();

         String address = "http://localhost:9000/helloWorld";

         Endpoint.publish(address, implementor);

    }

    public static void main(String args[]) throws Exception {

        new Server();

        System.out.println("Server ready...");

        Thread.sleep(5 * 60 * 1000);

        System.out.println("Server exiting");

        System.exit(0);

    }

}

运行后,在浏览器中输入http://localhost:9000/helloWorld?wsdl将显示这个web servicewsdl.说明web service发布成功。

4、    生成客户端代码

下面就开始创建一个客户端程序,访问这个web service, 同样新建java project ,并加入apache-cxf-2.0.7/lib所有包,由于CXF已经提供wsdl转化成java 的命令工具,所以创建一个build.xml,用来生成客户端程序。Bulid.xml内容如下:

<?xml version="1.0"?>

<project name="cxf wsdl2java" basedir=".">  

   <property name="cxf.home" location ="${basedir}/WebRoot/WEB-INF/"/>

   <path id="cxf.classpath">

      <fileset dir="${cxf.home}/lib">

         <include name="*.jar"/>

      </fileset>

   </path>     

   <target name="cxfWSDLToJava">

      <java classname="org.apache.cxf.tools.wsdlto.WSDLToJava" fork="true">

         <arg value="-client"/>

         <arg value="-d"/>

         <arg value="src"/>

         <arg value="http://localhost:9000/helloWorld?wsdl"/>

         <classpath>

            <path refid="cxf.classpath"/>

         </classpath>

      </java>

   </target>

</project>

或者:配置环境变量%CXF_HOME%=E:/WebService/CXF/apache-cxf-2.1.1/apache-cxf-2.1.1(以我的目录为例),并在PATH后加上;%CXF_HOME%/bin

cmd命令行中输入wsdl2java如果显示其用法表示配置好了。

输入:wsdl2java -d src - client http://localhost:9000/helloWorld?wsdl

其作用上面的build.xml作用一样。

附加:wsdl2java用法:

wsdl2java -p com -d src -all  aa.wsdl

-p  指定其wsdl的命名空间,也就是要生成代码的包名:

-d  指定要产生代码所在目录

-client 生成客户端测试web service的代码

-server 生成服务器启动web  service的代码

-impl 生成web service的实现代码

-ant  生成build.xml文件

-all 生成所有开始端点代码:types,service proxy,,service interface, server mainline, client mainline, implementation object, and an Ant build.xml file.

详细用法见:http://cwiki.apache.org/CXF20DOC/wsdl-to-java.html

5、    调用web service

import demo.hw.server.HelloWorld;

import demo.hw.server.HelloWorld_Service;

import demo.hw.server.IdentifiedUser;

import demo.hw.server.User;

import demo.hw.server.UserMap;

 

public class MyClient {

    public static void main(String[] argv) {

       HelloWorld hello = new HelloWorld_Service().getHelloWorldImplPort();

       User user = new User();

       user.setUsername("11111111111111");

       System.out.println(hello.sayUserHello(user));

       List<User> list = hello.findUsers();

       Iterator<User> i = list.iterator();

       while (i.hasNext()) {

           User u = i.next();

           System.out.println(u.getUsername());

       }

       UserMap map = hello.getMapUsers();

       for (IdentifiedUser e : map.getEntry()) {

           System.out.println(e.getId());

           System.out.println(e.getUser().getUsername());

       }

       }

}

原创粉丝点击