cxf使用JAXB数据绑定以及cxf对Map的支持
由于篇幅有限,此处生出源代码,如有需要的在评论里面留下联系的方式,笔者到时联系你。转载请标明读者链接,谢谢。
????? ? 一.JAXB简介
package com.syc.jaxb;import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;@XmlJavaTypeAdapter(UserAdapter.class)public interface User {String getName();}
此处注释的XmlJavaTypeAdapter是对自定义编组使用实现XmlAdapter的适配器,即UserAdapter这个类,该类实现了XmlAdapter适配器,因此要实现解组和编组两个方法。可能有的初学读者会提到:为什么我们要实现编组和解组呢?原因很简单,CXF不能直接支持List、Map等。
package com.syc.jaxb;import javax.xml.bind.annotation.XmlType;@XmlType(name="User")public class UserImpl implements User{String name;public UserImpl(){}public UserImpl(String n){this.name =n;}@Overridepublic String getName() {return name;}public void setName(String n){this.name = n ;}}?该类是实现了User接口,并且重写getName()方法,此类可以看成一个User实体类,其实也没有什么区别。这里注释的XmlType是将UserImpl映射到 XML 模式类型,即我们得到的客户端的时候显示的类的名字是User。
package com.syc.jaxb;import java.util.Map;import javax.jws.WebService;import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;@WebServicepublic interface HelloWorld {String sayHi(String text);String sayHiToUser(User user);@XmlJavaTypeAdapter(UserMapAdapter.class)Map<Integer,User> getUsers();}? 该接口是暴露的服务,该服务有三个方法,暴露的服务必须使用@WebService注释,不然在发布服务的时候找不到不要发布的服务类。由于第三个方法返回的是一个Map类型,但JAXB不能将一些Java类型自然映射到XML表示形式,例如,HashMap或者其他非JavaBean类。如参数类型为接口,以及Map,这需要特殊的XmlAdapter类进行处理。因此这里我们需要注释成让XmlAdapter适配器来处理。
package com.syc.jaxb;import java.util.LinkedHashMap;import java.util.Map;import javax.jws.WebService;@WebService(endpointInterface="com.syc.jaxb.HelloWorld",serviceName="HelloWorld")public class HelloWorldImpl implements HelloWorld {Map<Integer,User> users = new LinkedHashMap<Integer, User>();@Overridepublic String sayHi(String text) {System.out.println("sayHello called...");return "Hello " +text;}@Overridepublic String sayHiToUser(User user) {System.out.println("sayUserHello called...");users.put(users.size()+1, user);return "Hello"+ user.getName();}@Overridepublic Map<Integer, User> getUsers() {System.out.println("getMapUsers called...");return users;}}?该类是服务类的一个实现。
package com.syc.jaxb;import javax.xml.bind.annotation.adapters.XmlAdapter;public class UserAdapter extends XmlAdapter<UserImpl, User>{@Overridepublic User unmarshal(UserImpl v) throws Exception {return v;}@Overridepublic UserImpl marshal(User v) throws Exception {if(v instanceof UserImpl){return (UserImpl)v;}return new UserImpl(v.getName());}}?在这里,UserImpl是value类型,User是alue类型。UserAdapter类继承了XmlAdapter类,因此需要重写marshal()和unmarshal()方法,即编组和解组,在此处,编组就是将bound类型修改为value类型,然后将value类型编组为xml表示形式;解组就是JAXB绑定框架首先将XML表示形式解组为value类型,然后将value类型修改为bound类型。在这里我们可以这么理解,编组即bound->value->xml形式,解组即xml形式->value->bound。
package com.syc.jaxb;import java.util.ArrayList;import java.util.List;import java.util.Map;import javax.xml.bind.annotation.XmlAccessType;import javax.xml.bind.annotation.XmlAccessorType;import javax.xml.bind.annotation.XmlElement;import javax.xml.bind.annotation.XmlType;@XmlType(name="UserMap")@XmlAccessorType(XmlAccessType.FIELD)public class UserMap {@XmlElement(nillable=false,name="entry")List<UserEntry> entries = new ArrayList<UserEntry>();public List<UserEntry> getEntries() {return entries;}public void addEntry(UserEntry entry){entries.add(entry);}@XmlAccessorType(XmlAccessType.FIELD)@XmlType(name="UserEntry")static class UserEntry{public UserEntry(){super();}public UserEntry(Map.Entry<Integer, User> entry){super();this.id = entry.getKey();this.user = entry.getValue();}public UserEntry(Integer id,User user){super();this.id = id;this.user = user;}@XmlElement(required=true,nillable=false)Integer id;User user;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public User getUser() {return user;}public void setUser(User user) {this.user = user;}}}? UserMap类是让cxf支持MAP的关键,该类可以将map里面的key-value转换为User实体类,把key当作user的id值,把value当作user的name值,然后再把user保存到一个集合中,即实现了hash值到实体类的转换。
package com.syc.jaxb;import java.util.LinkedHashMap;import java.util.Map;import javax.xml.bind.annotation.adapters.XmlAdapter;public class UserMapAdapter extends XmlAdapter<UserMap, Map<Integer,User>>{@Overridepublic 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;}@Overridepublic UserMap marshal(Map<Integer, User> v) throws Exception {UserMap map = new UserMap();for(Map.Entry<Integer, User> e : v.entrySet()){UserMap.UserEntry u = new UserMap.UserEntry();u.setId(e.getKey());u.setUser(e.getValue());map.getEntries().add(u);}return map;}}?这里即对UserMap和Map对象的编组和解组。
package com.syc.jaxb;import javax.xml.ws.Endpoint;public class Server {public static void main(String[] args) {System.out.println("Starting Server... ");String address = "http://localhost:8899/hello";HelloWorldImpl implementor = new HelloWorldImpl();Endpoint.publish(address, implementor);try {Thread.sleep(5*60*1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Exiting Server... ");System.exit(0);}}用WSDL2JAVA生成的客户端,调用服务端代码?package com.syc.jaxb.client;import java.util.List;import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;public class HelloClient {public static void main(String[] args) {JaxWsProxyFactoryBean factoryBean = new JaxWsProxyFactoryBean();factoryBean.setAddress("http://localhost:8899/hello");factoryBean.setServiceClass(HelloWorld.class);HelloWorld h = (HelloWorld) factoryBean.create();System.out.println(h.sayHi("shenyc"));User u = new User();u.setName("syc");System.out.println(h.sayHiToUser(u));User u1 = new User();u1.setName("ssss");System.out.println(h.sayHiToUser(u1));User u2 = new User();u2.setName("aaaaa");System.out.println(h.sayHiToUser(u2));UserMap users = h.getUsers();List<UserEntry> list = users.getEntry();for(UserEntry ue : list){System.out.println(ue.getId()+":"+ue.getUser().getName());}}}?