An Example with Richer Data Types
在TimeServer的服务中,所提供的服务操作均无输入信息,同时返回简单数据类型,比如一个字符串或一个整数。本节我们将提供一个复杂一点的例子,具体实现细节将在下一章中介绍。
示例1-11中的Teams Web服务同前面的TimeServer服务有几个重要的区别。
示例1-11:带有复杂数据类型的Teams Web服务
- package ch01.team;
-
- import java.util.List;
- import javax.jws.WebService;
- import javax.jws.WebMethod;
-
- @WebService
- public class Teams {
- private TeamsUtility utils;
示例1-11:带有复杂数据类型的Teams Web服务(续例)
- public Teams() {
- utils = new TeamsUtility();
- utils.make_test_teams();
- }
-
- @WebMethod
- public Team getTeam(String name) { return utils.getTeam(name); }
-
- @WebMethod
- public List<Team> getTeams() { return utils.getTeams(); }
- }
第一,同前面TimeServer服务分别通过SEI和SIB来实现所不同的是,Team服务由一个单独的Java类实现。这种做法只是演示了这种实现上的可能性。另一个显著的区别就是两个Team服务操作所返回的数据类型不同。操作getTeam被参数化,同时返回预先定义的复杂Team对象类型,Team中包括一个仍然是预先定义的Player对象实例集合。服务操作返回getTeams一个Java List<Team>集合。
工具类TeamsUtility负责产生模拟数据。在一些正式的环境中,这个工具类可能从一个数据库中查询,或者获取一个team或一个team的集合列表。为了尽可能简单,TeamsUtility类并没有在运行中创建team和对应的player。下面是TeamsUtility类的主要代码:
- package ch01.team;
-
- import java.util.Set;
- import java.util.List;
- import java.util.ArrayList;
- import java.util.Map;
- import java.util.HashMap;
-
- public class TeamsUtility {
- private Map<String, Team> team_map;
-
- public TeamsUtility() {
- team_map = new HashMap<String, Team>();
- }
-
- public Team getTeam(String name) { return team_map.get(name); }
- public List<Team> getTeams() {
- List<Team> list = new ArrayList<Team>();
- Set<String> keys = team_map.keySet();
- for (String key : keys)
- list.add(team_map.get(key));
- return list;
- }
-
- public void make_test_teams() {
- List<Team> teams = new ArrayList<Team>();
- ...
- Player chico = new Player("Leonard Marx", "Chico");
- Player groucho = new Player("Julius Marx", "Groucho");
-
- Player harpo = new Player("Adolph Marx", "Harpo");
- List<Player> mb = new ArrayList<Player>();
- mb.add(chico); mb.add(groucho); mb.add(harpo);
- Team marx_brothers = new Team("Marx Brothers", mb);
- teams.add(marx_brothers);
-
- store_teams(teams);
- }
-
- private void store_teams(List<Team> teams) {
- for (Team team : teams)
- team_map.put(team.getName(), team);
- }
- }
- 发布服务并编写调用客户端
-
- Publishing the Service and Writing a Client
-
- 回想一下前面的TimeServer服务,在SEI中用到的注解:
-
- @SOAPBinding(style = Style.RPC)
这个注解只允许服务使用一些像字符串、整形等简单的数据类型。相反地是,Teams服务使用了更加复杂的数据类型,因此默认情况下须将Style.RPC替换为Style.DOCUMENT。Style.DOCUMENT类型需要更多配置,这些配置细节将在下一章详细介绍。下面就是部署这个Web服务和编写简单调用客户端的操作步骤。
1. 编译源文件。在当前工作目录中,仍然以ch01作为子目录,命令如下:
- % javac ch01/team/*.java
除了@WebService注解Teams类之外,在ch01/team目录中还包括Team、Player,TeamsUtility和TeamsPublisher类,如下所示:
- package ch01.team;
- public class Player {
- private String name;
- private String nickname;
-
- public Player() { }
- public Player(String name, String nickname) {
- setName(name);
- setNickname(nickname);
- }
-
- public void setName(String name) { this.name = name; }
- public String getName() { return name; }
- public void setNickname(String nickname) { this.nickname = nickname; }
- public String getNickname() { return nickname; }
- }
-
-
-
- package ch01.team;
-
- import java.util.List;
- public class Team {
- private List<Player> players;
- private String name;
-
- public Team() { }
- public Team(String name, List<Player> players) {
- setName(name);
- setPlayers(players);
- }
-
- public void setName(String name) { this.name = name; }
- public String getName() { return name; }
- public void setPlayers(List<Player> players)
- { this.players = players; }
- public List<Player> getPlayers() { return players; }
- public void setRosterCount(int n) { }
- public int getRosterCount() { return (players == null) ?
- 0 : players.size(); }
-
- }
- }
-
-
- package ch01.team;
- import javax.xml.ws.Endpoint;
- class TeamsPublisher {
- public static void main(String[ ] args) {
- int port = 8888;
- String url = "http://localhost:" + port + "/teams";
- System.out.println("Publishing Teams on port " + port);
- Endpoint.publish(url, new Teams());
- }
- }
2. 在当前工作目录中,执行随Java SE6发布的wsgen程序。
- % wsgen -cp . ch01.team.Teams
wsgen程序产生了不同的内容;其中有Endpoint.publish用来产生服务的WSDL文档Java类型,本书第2章将仔细地了解这些生成的内容,以及这些内容对WSDL产生怎样的帮助。
3. 执行TeamsPublisher程序。
4. 在工作目录下执行wsimport程序:
- % wsimport -p teamsC -keep http:
执行此命令后,将会在子目录teamsC中产生多个类文件(标志-p标示包名称)。通过生成的这些文件很简单地编写调用服务的客户端。
步骤4使得编写客户端的工作更加快捷,如下所示:
- import teamsC.TeamsService;
- import teamsC.Teams;
- import teamsC.Team;
- import teamsC.Player;
- import java.util.List;
- class TeamClient {
- public static void main(String[ ] args) {
- TeamsService service = new TeamsService();
- Teams port = service.getTeamsPort();
- List<Team> teams = port.getTeams();
- for (Team team : teams) {
- System.out.println("Team name: " + team.getName() +
- " (roster count: " + team.getRosterCount() + ")");
- for (Player player : team.getPlayers())
- System.out.println(" Player: " + player.getNickname());
- }
- }
- }
- 执行客户端,将输出如下内容:
-
- Team name: Abbott and Costello (roster count: 2)
- Player: Bud
- Player: Lou
- Team name: Marx Brothers (roster count: 3)
- Player: Chico
- Player: Groucho
- Player: Harpo
- Team name: Burns and Allen (roster count: 2)
- Player: George
- Player: Gracie
从这个例子可以看出,在商业级别上实现基于SOAP协议的Web服务哪些是可能完成的。只要遵循某种原则,一些自定义数据类型如Player、Team,以及以这些类型组成的任意集合类型等可以作为Web服务操作的参数传入或返回值返回。本例中已经使用了这些指导原则。针对Team和Player类,JavaBean的属性是String、int,或者是像List这样任何拥有toArray方法的Java集合对象。下一章涉及这些细节,尤其是wsgeng和wsimport工具在帮助JWS服务和客户端的快速开发上有哪些帮助作用。 |