项目中经常是处理复合类型比如集合List、Map,下面就cxf处理复合类型进行讲解。

具体例子如下:

   这里实例是客户端传一个JavaBean,服务器端返回集合类型;

 一、  接口返回List处理:

    在原来的项目实例(cxf开发webService服务端口)基础上,我们先创建一个实体类User:




java map类型不一样 java中的map类型_java map类型不一样

java map类型不一样 java中的map类型_java_02

1 /**
 2  * 
 3  */
 4 package com.hik.entity;
 5 
 6 /**
 7  * @ClassName: User
 8  * @Description: 用户实体类
 9  * @author jed
10  * @date 2017年7月30日下午2:44:41
11  *
12  */
13 public class User {
14 
15     private Integer id; // 编号
16     private String userName; //用户名
17     private String password; //密码
18     
19     public Integer getId() {
20         return id;
21     }
22     public void setId(Integer id) {
23         this.id = id;
24     }
25     public String getUserName() {
26         return userName;
27     }
28     public void setUserName(String userName) {
29         this.userName = userName;
30     }
31     public String getPassword() {
32         return password;
33     }
34     public void setPassword(String password) {
35         this.password = password;
36     }
37     
38     
39 }


View Code


再创建一个Role实体类:




java map类型不一样 java中的map类型_java map类型不一样

java map类型不一样 java中的map类型_java_02

1 /**
 2  * 
 3  */
 4 package com.hik.entity;
 5 
 6 /**
 7  * @ClassName: Role
 8  * @Description: TODO
 9  * @author jed
10  * @date 2017年7月30日下午2:46:45
11  *
12  */
13 public class Role {
14 
15     private Integer id; //编号
16     private String roleName; //角色名称
17     
18     public Role() {
19         super();
20     }
21 
22     public Role(Integer id, String roleName) {
23         super();
24         this.id = id;
25         this.roleName = roleName;
26     }
27     
28     public Integer getId() {
29         return id;
30     }
31     public void setId(Integer id) {
32         this.id = id;
33     }
34     public String getRoleName() {
35         return roleName;
36     }
37     public void setRoleName(String roleName) {
38         this.roleName = roleName;
39     }
40     
41     
42 }


View Code


然后HelloWorld再加一个接口方法getRoleByUser,通过用户查找角色:




java map类型不一样 java中的map类型_java map类型不一样

java map类型不一样 java中的map类型_java_02

1 /**
 2  * 
 3  */
 4 package com.hik.webservice;
 5 
 6 import java.util.List;
 7 
 8 import javax.jws.WebService;
 9 
10 import com.hik.entity.Role;
11 import com.hik.entity.User;
12 
13 /**
14  * @ClassName: HelloWorld
15  * @Description: TODO
16  * @author jed
17  * @date 2017年7月30日上午10:20:35
18  *
19  */
20 @WebService
21 public interface HelloWorld {
22 
23     public String say(String str);
24     
25     public List<Role> getRoleByUser(User user);
26 }


View Code


然后HelloWorld接口实现类 HelloWorldImpl写下新增的方法的具体实现,我们这里写死,模拟下即可:




java map类型不一样 java中的map类型_java map类型不一样

java map类型不一样 java中的map类型_java_02

1 /**
 2  * 
 3  */
 4 package com.hik.webservice.impl;
 5 
 6 import java.util.ArrayList;
 7 import java.util.List;
 8 
 9 import javax.jws.WebService;
10 
11 import com.hik.entity.Role;
12 import com.hik.entity.User;
13 import com.hik.webservice.HelloWorld;
14 
15 /**
16  * @ClassName: HelloWorldImpl
17  * @Description: TODO
18  * @author jed
19  * @date 2017年7月30日上午10:24:46
20  *
21  */
22 @WebService
23 public class HelloWorldImpl implements HelloWorld{
24 
25     public String say(String str) {
26         return "hello "+str;
27     }
28 
29     public List<Role> getRoleByUser(User user) {
30         List<Role> roleList = new ArrayList<Role>();
31         if(user!=null){
32             if(user.getUserName().equals("jack") && user.getPassword().equals("123456")){
33                 roleList.add(new Role(1, "技术总监"));
34                 roleList.add(new Role(2, "产品经理"));
35             }else if(user.getUserName().equals("lili") && user.getPassword().equals("123456")){
36                 roleList.add(new Role(3, "程序员"));
37             }
38             return roleList;
39         }else{
40             return null;
41         }
42                 
43     }
44 
45 }


View Code


服务端其他地方不用动;再重新发布下webService接口。

下面我们来处理下客户端,和前面讲的一样。我们用wsdl2java工具重新生成代码

java map类型不一样 java中的map类型_java map类型不一样_09

 

我们改下Client类:




java map类型不一样 java中的map类型_java map类型不一样

java map类型不一样 java中的map类型_java_02

1 /**
 2  * 
 3  */
 4 package com.hik.webservice;
 5 
 6 import java.util.List;
 7 
 8 /**
 9  * @ClassName: Client
10  * @Description: TODO
11  * @author jed
12  * @date 2017年7月30日下午1:58:36
13  *
14  */
15 public class Client {
16 
17     public static void main(String[] args) {
18         HelloWorldService service = new HelloWorldService();
19         HelloWorld helloWorld = service.getHelloWorldPort(); //代理
20         //System.out.println(helloWorld.say("你好!"));
21         User user = new User();
22         user.setUserName("lili");
23         user.setPassword("123456"); 
24         List<Role> roleList = helloWorld.getRoleByUser(user);
25         for(Role role : roleList){
26             System.out.println(role.getId()+" , "+role.getRoleName());
27         }
28     }
29 }


View Code


运行截图:

java map类型不一样 java中的map类型_java_12

二、接口返回Map处理

      map类型比较特殊,由其数据结构而决定。XmlAdapter类源码也有说明:

java map类型不一样 java中的map类型_Code_13

 因此,需要写一个适配器来做转换,使用注解annotation注解 。该适配器类需实现抽象类XmlAdapter的两个转换方法。

java map类型不一样 java中的map类型_List_14

 

 

java map类型不一样 java中的map类型_List_15

 代码例子如下:

  如增加接口:获取所有用用户以及对应的每个用户所有角色信息;

 

服务器端:

HelloWorld接口加方法:




java map类型不一样 java中的map类型_java map类型不一样

java map类型不一样 java中的map类型_java_02

1 /**
 2      * 
 3      * @MethodName: getRoles
 4      * @Description: 获取所有用户及对应角色
 5      * @author jed
 6      * @date 2017年8月4日下午10:36:59
 7      * @param @return    
 8      * @return Map<String,List<Role>>    返回类型
 9      * @return
10      *
11      */
12     @XmlJavaTypeAdapter(MapAdapter.class)
13     public Map<String, List<Role>> getRoles();


View Code


 

 HelloWorldImpl实现类加方法实现:




java map类型不一样 java中的map类型_java map类型不一样

java map类型不一样 java中的map类型_java_02

1 public Map<String, List<Role>> getRoles() {
 2         Map<String, List<Role>> map = new HashMap<String, List<Role>>();
 3         List<Role> roleList1 = new ArrayList<Role>();
 4         roleList1.add(new Role(1, "技术总监"));
 5         roleList1.add(new Role(2, "产品经理"));
 6         map.put("admin", roleList1);
 7         List<Role> roleList2 = new ArrayList<Role>();
 8         roleList2.add(new Role(3, "程序员"));
 9         map.put("jack", roleList2);
10         return map;
11     }


View Code


然后我们启动Server类:发现报错:

java map类型不一样 java中的map类型_Code_20

 报错显示不支持该类型,解决方案,可以使用适配器,把cxf不能接受的类型通过适配器,转能接受的类型。

 

      我们使用@XmlJavaTypeAdapter注解,加在接口定义上,完整接口代码如下:

 




java map类型不一样 java中的map类型_java map类型不一样

java map类型不一样 java中的map类型_java_02

1 /**
 2  * 
 3  */
 4 package com.hik.webservice;
 5 
 6 import java.util.List;
 7 import java.util.Map;
 8 
 9 import javax.jws.WebService;
10 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
11 
12 import com.hik.adapter.MapAdapter;
13 import com.hik.entity.Role;
14 import com.hik.entity.User;
15 
16 /**
17  * @ClassName: HelloWorld
18  * @Description: TODO
19  * @author jed
20  * @date 2017年7月30日上午10:20:35
21  *
22  */
23 @WebService
24 public interface HelloWorld {
25 
26     public String say(String str);
27     
28     /**
29      * 
30      * @MethodName: getRoleByUser
31      * @Description: 获取用户角色 
32      * @author jed
33      * @date 2017年8月4日下午10:37:30
34      * @param @param user
35      * @param @return    
36      * @return List<Role>    返回类型
37      * @param user
38      * @return
39      *
40      */
41     public List<Role> getRoleByUser(User user);
42     
43     /**
44      * 
45      * @MethodName: getRoles
46      * @Description: 获取所有用户及对应角色
47      * @author jed
48      * @date 2017年8月4日下午10:36:59
49      * @param @return    
50      * @return Map<String,List<Role>>    返回类型
51      * @return
52      *
53      */
54     @XmlJavaTypeAdapter(MapAdapter.class)
55     public Map<String, List<Role>> getRoles();
56 }


View Code


这里参数需要一个实现了XmlAdapter类的适配器类;

这里的话XmlAdapter要加两个参数,XmlAdapter<ValueType,BoundType> 

ValueType是cxf能接收的类型,这里我用了数组;

BoundType是cxf不能接受的类型,也就是我例子里的需求的Map类型;




java map类型不一样 java中的map类型_java map类型不一样

java map类型不一样 java中的map类型_java_02

1 /**
 2  * 
 3  */
 4 package com.hik.adapter;
 5 
 6 import java.util.HashMap;
 7 import java.util.List;
 8 import java.util.Map;
 9 
10 import javax.xml.bind.annotation.adapters.XmlAdapter;
11 
12 import com.hik.entity.Role;
13 
14 /**
15  * @ClassName: MapAdapter
16  * @Description: Map适配器
17  * @author jed
18  * @date 2017年8月4日下午10:56:41
19  *
20  */
21 public class MapAdapter extends XmlAdapter<MyRole[], Map<String, List<Role>>>{
22 
23     /**
24      * 适配转换  MyRole[] -> Map<String, List<Role>>
25      */
26     @Override
27     public Map<String, List<Role>> unmarshal(MyRole[] v) throws Exception {
28         Map<String, List<Role>> map = new HashMap<String, List<Role>>();
29         for(int i=0;i<v.length;i++){
30             MyRole r = v[i];
31             map.put(r.getKey(), r.getValue());
32         }
33         return map;
34     }
35 
36      /**
37      * 适配转换  Map<String, List<Role>> -> MyRole[]
38      */
39     @Override
40     public MyRole[] marshal(Map<String, List<Role>> v) throws Exception {
41         MyRole[] roles = new MyRole[v.size()];
42         int i=0;
43         for(String key : v.keySet()){
44             roles[i] = new MyRole();
45             roles[i].setKey(key);
46             roles[i].setValue(v.get(key));
47             i++;
48         }
49         
50         return roles;
51     }
52 
53 }


View Code


 

还有一个MyRole自定义类型,key:value。我们搞成两个属性,具体实现如下:




java map类型不一样 java中的map类型_java map类型不一样

java map类型不一样 java中的map类型_java_02

1 /**
 2  * 
 3  */
 4 package com.hik.adapter;
 5 
 6 import java.util.List;
 7 
 8 import com.hik.entity.Role;
 9 
10 /**
11  * @ClassName: MyRole
12  * @Description: 自定义实体 cxf能接受
13  * @author jed
14  * @date 2017年8月4日下午11:01:23
15  *
16  */
17 public class MyRole {
18 
19     private String key;
20     private List<Role> value;
21     
22     public String getKey() {
23         return key;
24     }
25     public void setKey(String key) {
26         this.key = key;
27     }
28     public List<Role> getValue() {
29         return value;
30     }
31     public void setValue(List<Role> value) {
32         this.value = value;
33     }
34     
35     
36 }


View Code


 

OK  好了。我们运行Server类,发布webservice接口:

java map类型不一样 java中的map类型_java map类型不一样_27

发布成功。然后就到了webservice客户端,我们用wsdl2java工具生成下最新代码

java map类型不一样 java中的map类型_List_28

 

我们修改下Client类:




java map类型不一样 java中的map类型_java map类型不一样

java map类型不一样 java中的map类型_java_02

1 /**
 2  * 
 3  */
 4 package com.hik.webservice;
 5 
 6 import java.util.List;
 7 
 8 /**
 9  * @ClassName: Client
10  * @Description: TODO
11  * @author jed
12  * @date 2017年7月30日下午1:58:36
13  *
14  */
15 public class Client {
16 
17     public static void main(String[] args) {
18         HelloWorldService service = new HelloWorldService();
19         HelloWorld helloWorld = service.getHelloWorldPort(); //代理
20         //System.out.println(helloWorld.say("你好!"));
21         /*User user = new User();
22         user.setUserName("lili");
23         user.setPassword("123456"); 
24         List<Role> roleList = helloWorld.getRoleByUser(user);
25         for(Role role : roleList){
26             System.out.println(role.getId()+" , "+role.getRoleName());
27         }*/
28         MyRoleArray array = helloWorld.getRoles();
29         List<MyRole> roleList = array.item;
30         for(int i=0;i<roleList.size();i++){
31             MyRole mr = roleList.get(i);
32             System.out.println(mr.key+":");
33             for(Role r: mr.getValue()){
34                 System.out.println(r.getId()+","+r.getRoleName()+" ");
35             }
36             System.out.println();
37         }
38     }
39 }


View Code


运行结果:

java map类型不一样 java中的map类型_Code_31

 

    总结: webService处理过程如下:

1、webservice服务器端开发webservice接口,然后发布webservice;

2、通过一个Url调用webservice接口,发布的url是 http://192.168.0.102/helloWorld,则我们请求的url就是 http://192.168.0.102/helloWorld?wsdl  

3、请求成功,返回一大串xml标记。这一大串xml即使wsdl。   wsdl (Web Services Description Language) 也就是Web Service描述语言,描述服务器端定义的webservice接口的相关信息。

4、wsdl描述可看到发布的方法。如:wsdl:types就是定义了一些变量,wsdl:message相当于定义方法,wsdl:portType相当与调用与返回。

5、客户端通过这个url请求,获得wsdl规范的xml文档片段信息,需用到SOAP(Simple Object Access Protocol)即简单对象访问协议,我们通过这个协议,来实现客户端,服务器端消息交互,SOAP使用XML消息调用远程方法;

     当然交互的媒介就是xml,具体交互内容根据wsdl文档描述来。