相关dependency,我使用的版本是2.7.11:
<dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>${cxf.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>${cxf.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http-jetty</artifactId> <version>${cxf.version}</version> </dependency>
以一个简单的Service为例:
import javax.jws.WebMethod; import javax.jws.WebService; @WebService public interface MyCxfService { @WebMethod String saySth(String content); }
以及其实现:
import org.apache.cxf.jaxws.JaxWsProxyfactorybean; import org.apache.cxf.jaxws.JaxWsServerfactorybean; import pac.testcase.ws.MyCxfService; public class MyCxfServiceImpl implements MyCxfService { public String saySth(String content) { return "I say "+content; } }
启动服务:
JaxWsServerfactorybean server = new JaxWsServerfactorybean(); server.setServiceClass(MyCxfServiceImpl.class); server.setAddress("http://localhost:8686/ws/service"); server.create();
调用服务:
JaxWsProxyfactorybean client = new JaxWsProxyfactorybean(); client.setServiceClass(MyCxfService.class); client.setAddress("http://localhost:8686/ws/service"); MyCxfService service = (MyCxfService)client.create(); System.out.println(service.saySth("nothing but performance!!"));
CXF是通过Spring为service提供XML配置的。
需要用Servlet Listener装载Spring后加入CXF相关的Servlet。
也就是说:
<servlet> <servlet-name>CXFServlet</servlet-name> <display-name>CXF Servlet</display-name> <servlet-class> org.apache.cxf.transport.servlet.CXFServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping>
在spring的配置文件中加入xmlns:
xmlns:jaxws="http://cxf.apache.org/jaxws"
和xsi:schemaLocation:
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
继续用上一个例子中的Service接口,简单做一下配置:
<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"/> <jaxws:endpoint implementor="pac.king.webservice.impl.MyCxfServiceImpl" address="/MyCxfService" />
访问:http://localhost:8080/runtrain/services/,会出现下面的效果:
客户端方面,可以使用jaxws:client配置让他调用本地bean那样简单:
<jaxws:client id="MyCxfClient" address="http://localhost:8080/runtrain/services/MyCxfService" serviceClass="pac.king.webservice.MyCxfService" />
如果不使用则相当于:
<bean id="MyCxfClient" factory-bean="clientFactory" factory-method="create"/> <bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyfactorybean" p:serviceClass="pac.king.webservice.MyCxfService" p:address="http://localhost:8080/runtrain/services/MyCxfService" />
远程调用变得透明:
ApplicationContext context = new ClasspathXmlApplicationContext("classpath*:applicationContext*.xml"); MyCxfService client = (MyCxfService)context.getBean("MyCxfClient"); System.out.println(client.saySth("nothing but show!!"));
曾经想过一个问题,为什么我自己定义个User类什么的都可以传输,而Map却不可以?
天天堆砌API导致很多人把这个Map想得太简单了,换个立场想想,XSD如何去表示Map这种东西?
JAXB(Java Architecture for XML Binding)可以解决这个问题!
简单说来就是:
Java Architecture for XML Binding (JAXB) allows Java developers to map Java classes to XML representations. JAXB provides two main features: the ability to marshal Java objects into XML and the inverse,i.e. to unmarshal XML back into Java objects.
这里引用一下wiki中XSD与JAXB对对照:
XML Schema Type | Java Data Type | |||||||
---|---|---|---|---|---|---|---|---|
xsd:string |
java.lang.String |
|||||||
xsd:integer |
java.math.BigInteger |
|||||||
xsd:positiveInteger |
xsd:int |
int |
||||||
xsd:long |
long |
|||||||
xsd:short |
short |
|||||||
xsd:decimal |
java.math.BigDecimal |
|||||||
xsd:float |
float |
|||||||
xsd:double |
double |
|||||||
xsd:boolean |
boolean |
|||||||
xsd:byte |
byte |
|||||||
xsd:QName |
javax.xml.namespace.QName |
|||||||
xsd:dateTime |
javax.xml.datatype.XMLGregorianCalendar |
|||||||
xsd:base64Binary |
byte[] |
|||||||
xsd:hexBinary |
xsd:unsignedInt |
xsd:unsignedShort |
xsd:unsignedByte |
xsd:unsignedLong |
xsd:time |
xsd:date |
xsd:g |
javax.xml.datatype.XMLGregorianCalendar |
xsd:anySimpleType
|
java.lang.Object |
|||||||
xsd:anySimpleType |
xsd:duration |
javax.xml.datatype.Duration |
||||||
xsd:NOTATION |
javax.xml.namespace.QName |
简单记录一下操作步骤。
首先我需要写一个Adapter来进行marsal/unmarshal。
可以使用javax.xml.bind.annotation.adapters.XmlAdapter<ValueType,BoundType>
简单说来就是用前者解释后者,引用一下javaDoc中对ValueType与BoundType的说明:
* @param <BoundType> * The type that JAXB doesn't kNow how to handle. An adapter is written * to allow this type to be used as an in-memory representation through * the <tt>ValueType</tt>. * @param <ValueType> * The type that JAXB kNows how to handle out of the Box.
我现在试着写一个返回Map的方法,但是我不能用java.util.Map,因为JAXB无法处理interface。
于是我这样定义我的服务:
import java.util.HashMap; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import pac.king.pojo.User; import pac.king.webservice.utils.MyMapAdapter; @WebService public interface MyCxfService { @WebMethod @XmlJavaTypeAdapter(MyMapAdapter.class) public @WebResult HashMap<String,String> convertUserInfoToMap(@WebParam User user); }
以及实现:
import java.util.HashMap; import pac.king.pojo.User; import pac.king.webservice.MyCxfService; public class MyCxfServiceImpl implements MyCxfService { public HashMap<String,String> convertUserInfoToMap(User user) { HashMap<String,String> result = new HashMap<String,String>(); result.put("name",user.getName()); result.put("id",user.getId()); result.put("password",user.getpassword()); return result; } }
写User时需要提供一个没有参数的constructor:
package pac.king.pojo; public class User { private String id; private String name; private String password; public String getpassword() { return password; } public void setPassword(String password) { this.password = password; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public User() {} public User(String id,String name,String password) { super(); this.id = id; this.name = name; this.password = password; } }
注意服务方法上的注解@XmlJavaTypeAdapter(MyMapAdapter.class)。
这是继承XmlAdapter写的一个Adapter:
import java.util.HashMap; import java.util.Map.Entry; import javax.xml.bind.annotation.adapters.XmlAdapter; public class MyMapAdapter extends XmlAdapter<MyGeneralBean[],HashMap<String,String>>{ @Override public HashMap<String,String> unmarshal(MyGeneralBean[] v) throws Exception { HashMap<String,String> resultMap = new HashMap<String,String>(); for (MyGeneralBean e : v) { resultMap.put(e.getKey(),e.getValue()); } return resultMap; } @Override public MyGeneralBean[] marshal(HashMap<String,String> v) throws Exception { MyGeneralBean[] m = new MyGeneralBean[10]; int i=0; for (Entry<String,String> entry : v.entrySet()) { m[++i] = new MyGeneralBean(entry.getKey(),entry.getValue()); } return m; } }
MyGeneralBean是用来解释Map结构的一个简单类型,这个也需要提供一个无参数的constructor:
public class MyGeneralBean { private String key; private String value; public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public MyGeneralBean() {} public MyGeneralBean(String key,String value) { super(); this.key = key; this.value = value; } }
这样就可以调用了,继续使用上一个例子中的jaxws:client配置,直接使用服务。
ApplicationContext context = new ClasspathXmlApplicationContext("classpath*:applicationContext*.xml"); MyCxfService client = (MyCxfService) context.getBean("MyCxfClient"); Map<String,String> map = client.convertUserInfoToMap(new User("100001","King.","t;stmdtkg")); System.out.println(map.get("id")); System.out.println(map.get("name")); System.out.println(map.get("password"));
输出:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。