上一篇文章中概述了怎麼在Javaweb中發佈webservice,這篇文章講解怎麼傳遞複雜的對象java
所用的jar包以下web
![在此輸入圖片描述][1] (圖掛了看這裏:http://cafebabe.cn/study/2015/11/26/spring-restful-webservice ) 當服務器返回的是List或者是Map時,必定要將其封裝在一個類中,spring
首先建立封裝類,封裝了List,Map對象,以及自定義的User類apache
User.javajson
public class User { private String name; private int age; public User() { } public User(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User [age=" + age + ", name=" + name + "]"; } }
DataResult.java瀏覽器
@XmlRootElement public class DataResult { private List<User> userList; private Map<String,User> userMap; public List<User> getUserList() { return userList; } public void setUserList(List<User> userList) { this.userList = userList; } public Map<String, User> getUserMap() { return userMap; } public void setUserMap(Map<String, User> userMap) { this.userMap = userMap; } /** * 爲了測試時方便輸出重寫的一個toString()方法 */ public String toString(){ for(User u:userList){ System.out.println(u); } Set<String> key = userMap.keySet(); for (Iterator it = key.iterator(); it.hasNext();) { String s = (String) it.next(); System.out.println(s + "-->" + userMap.get(s)); } return "end"; } }
建立webservice服務接口服務器
@Path(value = "/get") public interface TestService { @GET @Path("/listMap1") @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public List<Map> getListMap1(); @GET @Path("/listMap") @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public List<Map> getListMap(); @GET @Path("/dataResult") @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public DataResult getMap(); @GET @Path("/string/{param}") @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public String getName(@PathParam("param")String param); }
建立服務接口實現類restful
/** * webservice服務實現類 * @author 那位先生 * */ @Path(value = "/get") public class TestServiceImpl implements TestService{ /** * @see com.webservice.service.TestService#getListMap1() * 傳遞 List<Map<String,User>> */ @Override @GET @Path("/listMap1") @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @XmlJavaTypeAdapter(MapAdapter.class) public List<Map> getListMap1() { List<Map> listMap = new ArrayList<Map>(); for (int i = 0; i < 5; i++) { Map map = new HashMap<String,User>(); for (int j = 0; j < 5; j++) { User user=new User("user"+j,new Random().nextInt()); map.put("key" + i + j, user); } listMap.add(map); } return listMap; } /** * @see com.webservice.service.TestService#getListMap() * 傳遞 List<Map<String,String>> * */ @Override @GET @Path("/listMap") @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @XmlJavaTypeAdapter(MapAdapter.class) public List<Map> getListMap() { List<Map> listMap = new ArrayList<Map>(); for (int i = 0; i < 5; i++) { Map map = new HashMap(); for (int j = 0; j < 5; j++) { map.put("key" + i + j, "value" + i + j); } listMap.add(map); } return listMap; } /** * 傳遞List,Map時須要封裝到一個類中 * * */ @Override @GET @Path("/dataResult") @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public DataResult getMap() { DataResult result=new DataResult(); List<User> userList=new ArrayList<User>(); Map<String,User> userMap=new HashMap<String,User>(); for(int i=0;i<5;i++){ User user=new User("user"+i,new Random().nextInt()); userList.add(user); userMap.put("key"+i, user); } result.setUserList(userList); result.setUserMap(userMap); return result; } /** * 傳遞String * */ @Override @GET @Path("/string/{param}") @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public String getName(@PathParam("param")String param) { return param; } }
由於在webservice服務中要傳遞List<Map>對象,這個不能直接傳或者封裝到某個類中,須要用到適配器和轉換器app
MapAdapter.javadom
public class MapAdapter extends XmlAdapter<MapConvertor, Map<String, Object>> { @Override public MapConvertor marshal(Map<String, Object> map) throws Exception { MapConvertor convertor = new MapConvertor(); for(Map.Entry<String, Object> entry:map.entrySet()){ MapConvertor.MapEntry e = new MapConvertor.MapEntry(entry); convertor.addEntry(e); } return convertor; } @Override public Map<String, Object> unmarshal(MapConvertor map) throws Exception { Map<String, Object> result = new HashMap<String,Object>(); for(MapConvertor.MapEntry e :map.getEntries()){ result.put(e.getKey(), e.getValue()); } return result; } }
MapConvertor.java
@XmlType(name = "MapConvertor") @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement @XmlSeeAlso({User.class})//若是傳遞的是List<Map<String,User>>,必需要@XmlSeeAlso註解 public class MapConvertor { private List<MapEntry> entries = new ArrayList<MapEntry>(); public void addEntry(MapEntry entry) { entries.add(entry); } public static class MapEntry { public MapEntry() { super(); } public MapEntry(Map.Entry<String, Object> entry) { super(); this.key = entry.getKey(); this.value = entry.getValue(); } public MapEntry(String key, Object value) { super(); this.key = key; this.value = value; } private String key; private Object value; public String getKey() { return key; } public void setKey(String key) { this.key = key; } public Object getValue() { return value; } public void setValue(Object value) { this.value = value; } } public List<MapEntry> getEntries() { return entries; } }
還有過濾器,這個沒怎麼研究,因此隨便實現了一下
TestInterceptor.java
public class TestInterceptor extends AbstractPhaseInterceptor<Message> { public TestInterceptor() { super(Phase.RECEIVE); } public TestInterceptor(String phase) { super(phase); } @Override public void handleMessage(Message arg0) throws Fault { System.out.println("handleMessage()"); } }
最後所有交由spring容器管理
webservice-server.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> <bean id="testServiceInterceptor" class="com.webservice.interceptor.TestInterceptor" /> <bean id="service" class="com.webservice.service.impl.TestServiceImpl" /> <jaxrs:server id="testServiceContainer" address="/test"> <jaxrs:serviceBeans> <ref bean="service" /> </jaxrs:serviceBeans> <jaxrs:inInterceptors> <ref bean="testServiceInterceptor" /> </jaxrs:inInterceptors> <jaxrs:extensionMappings> <entry key="json" value="application/json" /> <entry key="xml" value="application/xml" /> </jaxrs:extensionMappings> <jaxrs:languageMappings> <entry key="cn" value="cn-ZH"/> </jaxrs:languageMappings> </jaxrs:server> </beans>
在web.xml中配置webservice的cxf Servlet以及spring容器
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/webservice-server.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> </servlet> <!-- 設置訪問的目錄 --> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
要注意的是 服務器默認返回的是xml格式數據,當要返回json時則在路徑後加 "?_type=json"便可,例如 http://localhost:8080/webservice/services/test/get/string/testString?_type=json
訪問其餘查看結果: http://localhost:8080/webservice/services/test/get/string/testString?_type=json (訪問這裏時若是不返回json,返回xml,瀏覽器會顯示解析xml失敗,不知道爲何,因此在這裏最好是返回json) http://localhost:8080/webservice/services/test/get/dataResult http://localhost:8080/webservice/services/test/get/listMap http://localhost:8080/webservice/services/test/get/listMap1
接下來建立webservice客戶端,在這裏爲了方便測試,將客戶端和服務器端寫在一塊兒
ClientTest.java
public class ClientTest { public static void main(String[] args) { ClientTest test = new ClientTest(); String result = test.getResultString("success"); System.out.println(result); } /** * 獲取List<Map<String,User>> * */ public List<Map<String, User>> getListMap2() { WebClient client = getClientBySpring(); String xml = client.path("get/listMap1").accept("application/xml").get( String.class); List<Map<String, User>> listMap = null; try { // 沒法從服務器中直接獲取List<Map>對象,因此只能獲取xml,將其解析成List<Map> listMap = XmlParse.parseToListMap2(xml); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return listMap; } /** * 獲取List<Map<String, String>> * */ public List<Map<String, String>> getListMap1() { WebClient client = getClientBySpring(); String xml = client.path("get/listMap").accept("application/xml").get( String.class); List<Map<String, String>> listMap = null; try { // 沒法從服務器中直接獲取List<Map>對象,因此只能獲取xml,將其解析成List<Map> listMap = XmlParse.parseToListMap1(xml); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return listMap; } /** * 獲取封裝類 * */ public DataResult getDataResult() { WebClient client = getClientBySpring(); DataResult result = client.path("get/dataResult/") .get(DataResult.class); return result; } /** * 獲取字符串結果 * */ public String getResultString(String param) { WebClient client = getClientBySpring(); String result = client.path("get/string/" + param).get(String.class); return result; } /** * 打印map * */ private void printMap(Map<String, String> map) { Set<String> key = map.keySet(); for (Iterator it = key.iterator(); it.hasNext();) { String s = (String) it.next(); System.out.println(s + "-->" + map.get(s)); } } /** * * 從spring中獲取client * */ private WebClient getClientBySpring() { ApplicationContext ctx = new ClassPathXmlApplicationContext( "webservice-client.xml"); WebClient client = ctx.getBean("webClient", WebClient.class); return client; } /** * 直接獲取client * */ private WebClient getClientByCode() { String url = "http://localhost:8080/webservice/services/test/"; WebClient client = WebClient.create(url); return client; } }
XmlParse.java
/** * XML解析類 * */ public class XmlParse { public static List<Map<String,User>> parseToListMap2(String content) throws ParserConfigurationException, SAXException, IOException{ List<Map<String,User>> listMap=new ArrayList<Map<String,User>>(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document document = db.parse(new InputSource(new StringReader(content))); NodeList list = document.getElementsByTagName("mapConvertor"); for (int i = 0; i < list.getLength(); i++) { Element element = (Element) list.item(i); Map<String,User> map=new HashMap<String,User>(); NodeList entries=element.getElementsByTagName("entries"); for(int j=0;j<entries.getLength();j++){ Element entrie=(Element)entries.item(j); String key = entrie.getElementsByTagName("key").item(0).getTextContent(); String age = entrie.getElementsByTagName("value").item(0).getFirstChild().getTextContent(); String name = entrie.getElementsByTagName("value").item(0).getLastChild().getTextContent(); User user=new User(name,Integer.parseInt(age)); map.put(key, user); } listMap.add(map); } return listMap; } public static List<Map<String,String>> parseToListMap1(String content) throws ParserConfigurationException, SAXException, IOException{ List<Map<String,String>> listMap=new ArrayList<Map<String,String>>(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document document = db.parse(new InputSource(new StringReader(content))); NodeList list = document.getElementsByTagName("mapConvertor"); for (int i = 0; i < list.getLength(); i++) { Element element = (Element) list.item(i); Map<String,String> map=new HashMap<String,String>(); NodeList entries=element.getElementsByTagName("entries"); for(int j=0;j<entries.getLength();j++){ Element entrie=(Element)entries.item(j); String key = entrie.getElementsByTagName("key").item(0).getTextContent(); String value = entrie.getElementsByTagName("value").item(0).getTextContent(); map.put(key, value); } listMap.add(map); } return listMap; } }
能夠將客戶端交由spring管理
spring-client.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <bean id="webClient" class="org.apache.cxf.jaxrs.client.WebClient" factory-method="create"> <constructor-arg type="java.lang.String" value="http://localhost:8080/webservice/services/test/" /> </bean> </beans>
至此大功告成。
PS:在學習webservice的時候,遇到過幾個問題,但願有了解的可以告知,能夠在個人博客下留言,,先謝謝了,問題以下 1)在訪問http://localhost:8080/webservice/services/test/get/string/testString?_type=json 時,若是不加「_type=json」,瀏覽器會報錯,不知道爲何,因此訪問字符串時只能用返回json格式 2)對於返回的List<Map>對象須要使用的轉換器來實現,若是服務器返回的是一個普通類對象,但這個對象中存在List<Map>,該怎麼辦呢?我在osc上提到過,但沒有獲得回答。 [1]: http://static.oschina.net/uploads/space/2014/0727/161600_5fdW_43830.png