項目中經常是處理復合類型比如集合List、Map,下面就cxf處理復合類型進行講解。
具體例子如下:
這里實例是客戶端傳一個JavaBean,服務器端返回集合類型;
一、 接口返回List處理:
在原來的項目實例(cxf開發webService服務端口)基礎上,我們先創建一個實體類User:

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 }
再創建一個Role實體類:

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 }
然后HelloWorld再加一個接口方法getRoleByUser,通過用戶查找角色:

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 }
然后HelloWorld接口實現類 HelloWorldImpl寫下新增的方法的具體實現,我們這里寫死,模擬下即可:

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 }
服務端其他地方不用動;再重新發布下webService接口。
下面我們來處理下客戶端,和前面講的一樣。我們用wsdl2java工具重新生成代碼(參考cxf開發webService客戶端及調用服務端的理解 )
我們改下Client類:

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 }
運行截圖:
二、接口返回Map處理
map類型比較特殊,由其數據結構而決定。XmlAdapter類源碼也有說明:
因此,需要寫一個適配器來做轉換,使用注解annotation注解 。該適配器類需實現抽象類XmlAdapter的兩個轉換方法。
代碼例子如下:
如增加接口:獲取所有用用戶以及對應的每個用戶所有角色信息;
服務器端:
HelloWorld接口加方法:

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();
HelloWorldImpl實現類加方法實現:

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 }
然后我們啟動Server類:發現報錯:
報錯顯示不支持該類型,解決方案,可以使用適配器,把cxf不能接受的類型通過適配器,轉能接受的類型。
我們使用@XmlJavaTypeAdapter注解,加在接口定義上,完整接口代碼如下:

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 }
這里參數需要一個實現了XmlAdapter類的適配器類;
這里的話XmlAdapter要加兩個參數,XmlAdapter<ValueType,BoundType>
ValueType是cxf能接收的類型,這里我用了數組;
BoundType是cxf不能接受的類型,也就是我例子里的需求的Map類型;

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 }
還有一個MyRole自定義類型,key:value。我們搞成兩個屬性,具體實現如下:

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 }
OK 好了。我們運行Server類,發布webservice接口:
發布成功。然后就到了webservice客戶端,我們用wsdl2java工具生成下最新代碼
我們修改下Client類:

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 }
運行結果:
總結: 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文檔描述來。