精华帖 (0) :: 良好帖 (2) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-11-28
最后修改:2009-11-29
在选择WebService框架的过程中,偶最终选择了Apache CXF,純粹伿諟銦爲听说它与Spring的无缝整合 想当初用Axis的时候,因为没有太好的办法让Spring能够集成Axis,只好平白无故地多出一个WebService代理类,让偶的感觉很是不爽
偶要在此记载一下CXF的一些入门知识 首珗,倌網哋址諟http://cxf.apache.org/,里面可以找到User's Guide和download地址,偶的版本是目前最新的 apache-cxf-2.2.5
先来做一个最简单的入门级别例子吧,也就是经典的HelloWord Server端代码 WebService接口HelloService.java package cfx.server; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebService; @WebService public interface HelloService { @WebMethod String sayHi(@WebParam String name); } 实现类HelloServiceImpl.java public class HelloServiceImpl implements HelloService { public String sayHi(String name) { System.out.println("HelloServiceImpl.sayHi called"); return "Hello"+name; } WebService配置文件:cxf-servlet.xml(可放置于WEB-INF目录下) <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:soap="http://cxf.apache.org/bindings/soap" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <jaxws:server id="jaxwsService" serviceClass="cfx.server.HelloService" address="/hello"> <jaxws:serviceBean> <bean class="cfx.server.HelloServiceImpl" /> </jaxws:serviceBean> </jaxws:server> </beans> web.xml代码,用于添加CXFServlet这个处理webservice请求的控制器类 <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <servlet> <description>Apache CXF Endpoint</description> <display-name>cxf</display-name> <servlet-name>cxf</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>cxf</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> <session-config> <session-timeout>60</session-timeout> </session-config> </web-app> Client端测试代码 public class CXF { public static void main(String[] args) { JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.getInInterceptors().add(new LoggingInInterceptor()); factory.getOutInterceptors().add(new LoggingOutInterceptor()); factory.setServiceClass(HelloService.class); factory.setAddress("http://localhost:8080/cxf/services/hello"); HelloService client = (HelloService) factory.create(); String reply = client.sayHi("特蕾莎"); System.out.println("Server said: " + reply); } ***************************************************************************** 怎么样,是不是很简单啊!现在再来一个和Spring整合的例子 注意,Server端和Client端都要通过Spring-bean的方式整合 Server端现在有四个文件,假设是 HelloService.java HelloServiceImpl.java HelloDao.java HelloDaoImpl.java 在HelloServiceImpl中存在一个HelloDao的属性,代码省略如下 public class HelloServiceImpl implements HelloService { private HelloDao dao; public String sayHi(String name) { System.out.println("HelloServiceImpl.sayHi called"); return dao.getString(name); } } HelloDaoImpl用于处理持久化,代码省略咯 需要修改的是配置文件,此时可以这样改 首先在web.xml里加入Spring监听器 <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext*.xml</param-value> </context-param> <servlet> <description>Apache CXF Endpoint</description> <display-name>cxf</display-name> <servlet-name>cxf</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>cxf</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> <session-config> <session-timeout>60</session-timeout> </session-config> </web-app> 橪銗WEB-INF/cxf-servlet這個忟件可以省略咯 把一个标准的spring-bean文件放在src下(即classes目录下),要让人一看就知道spring大哥进来咯 applicationContext.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.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="helloDao" class="cfx.server.HelloDaoImpl" /> <jaxws:server id="jaxwsService" serviceClass="cfx.server.HelloService" address="/hello"> <jaxws:serviceBean> <bean id="helloService" class="cfx.server.HelloServiceImpl"> <property name="dao" ref="helloDao" /> </bean> </jaxws:serviceBean> </jaxws:server> </beans>
這樣啟動服務器的时候,spring就自动进行bean的注入以及WebService服务的发布了 接下来是客户端代码 銦爲諟普通Java,所以就简单配一下愙戸端的spring文件了 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schema/jaxws.xsd"> <bean id="HelloService" class="cfx.server.HelloService" factory-bean="clientFactory" factory-method="create" /> <bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean"> <property name="serviceClass" value="cfx.server.HelloService" /> <property name="address" value="http://localhost:8080/cxf/services/hello" /> </bean> </beans> CXFClientTest.java public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "cfx/client/client-beans.xml" }); HelloService client = (HelloService) context.getBean("HelloService"); testString(client); } static void testString(HelloService client) { String reply = client.sayHi("特蕾莎"); System.out.println("Server said: " + reply); } *************************************************************************
然后是复杂数据类型的问题,经过测试,发觉基本数据类型和List都是没有问题的,我的测试方法包括 @WebMethod String sayHi(@WebParam String name); @WebMethod List<Integer> getList(@WebParam List<String> strs); @WebMethod List<User> getJavaBean();
但是传递Map时,就出现问题了,所以参照了user's guide,得到如下解决办法 测试某个方法的参数和返回值都是Map类型 @WebMethod @XmlJavaTypeAdapter(MapAdapter.class) Map<String, String> getMap(@WebParam @XmlJavaTypeAdapter(MapAdapter.class) Map<String, String> map);
MapAdapter是我自己写的用於數據類型轉換的适配器类,代码如下 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 Map格式转换类 @XmlType(name = "MapConvertor") @XmlAccessorType(XmlAccessType.FIELD) 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; } } 经过这个MapAdapter,算是完成了Map类型的数据传递 接下来,就是更为复杂的一点的这种情况了:List<Map<String,Object>> 这个情况实在不太好办,目前偶也没有找到更好的办法,偶只能这样做 @WebMethod List<MapConvertor> getListMap(List<MapConvertor> listmap);
就是把MapConvertor当成Map来使,但偶觉得这不是一个很妥善的办法。
其实偶觉得,WebService里应该尽量减少使用javabean对象进行传输 一个JavaBean可以转换成一个Map 一个包含多个JavaBean的List可以转换成一个包含多个Map的List 所以如果对Map支持得好的话,就应该多用Map和List来实现数据传递 当然在调用的时候,也最好能够像Axis一样使用Call来实现无接口调用 这样在Client端就不需要得到Server提供的任何jar了 这样才是最松散耦合的系统 只可惜现在对Map支持得不是很好,最起码在List<Map>时用的方式感觉不太好
不知道各位GGJJ们是怎么做的呢? 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-12-05
这样更省事
package cn.com.pansky.dss.common.ws; import java.util.HashMap; import javax.xml.bind.annotation.adapters.XmlAdapter; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; /** * XML to Map及Map to XML序列化 * @author shenwujie * */ public class MapAdapter extends XmlAdapter<String,HashMap> { @Override public String marshal(HashMap map) throws Exception { XStream xs = new XStream(new DomDriver()); return xs.toXML(map); } @Override public HashMap unmarshal(String xmlData) throws Exception { XStream xs = new XStream(new DomDriver()); return (HashMap) xs.fromXML(xmlData); } } |
|
返回顶楼 | |
发表时间:2010-02-02
博主,你的
@WebMethod List<User> getJavaBean(); 这个方法是怎么弄的啊????????????????? |
|
返回顶楼 | |
发表时间:2010-03-02
如果方法中用了这种map 会提示一下内容,请问该如何解决呢
警告: {http://service.ws.upc.red.com/}findUser requires a wrapper bean but problems with ASM has prevented creating one. Operation may not work correctly. |
|
返回顶楼 | |
发表时间:2010-07-05
楼主,用MAP作为数据传递的能数。在客户端是要构建一个MapConvertor将MapEntry作为他的参数。MapEntry只能是一对key,value.要是要多个要用List<MapEntry>。再把这个List<MapEntry>赋给MapConvertorr的entries。楼主是这样的吗。
MapEntry不能像MAP这样添加多组<key,value>。如何能实现这样的功能。 |
|
返回顶楼 | |
发表时间:2010-09-15
这娃比较懒! 嘎嘎
|
|
返回顶楼 | |
发表时间:2010-10-22
kiki 写道 这样更省事
package cn.com.pansky.dss.common.ws; import java.util.HashMap; import javax.xml.bind.annotation.adapters.XmlAdapter; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; /** * XML to Map及Map to XML序列化 * @author shenwujie * */ public class MapAdapter extends XmlAdapter<String,HashMap> { @Override public String marshal(HashMap map) throws Exception { XStream xs = new XStream(new DomDriver()); return xs.toXML(map); } @Override public HashMap unmarshal(String xmlData) throws Exception { XStream xs = new XStream(new DomDriver()); return (HashMap) xs.fromXML(xmlData); } } 这种方式要求客户端也要发送一个xml字符串,让为客户端也xStream转码?还是你告诉调用者map类型数据,就转成对应的xml? |
|
返回顶楼 | |
浏览 15141 次