项目中经常是处理复合类型比如集合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 }
View Code
再创建一个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 }
View Code
然后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 }
View Code
然后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 }
View Code
服务端其他地方不用动;再重新发布下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 }
29 }
View Code
运行截图:
二、接口返回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();
View Code
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 }
View Code
然后我们启动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 }
View Code
这里参数需要一个实现了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 }
View Code
还有一个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 }
View Code
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 }
View Code
运行结果:
总结: 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文档描述来。