您的位置:首页 > 运维架构 > Apache

【Apache CXF】CXF对JAX-WS的支持

2014-05-09 16:00 295 查看
相关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[/code]继续用上一个例子中的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 TypeJava Data Type
xsd:string
java.lang.String
xsd:integer
java.math.BigInteger
xsd:positiveInteger
java.math.BigInteger
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
byte[]
xsd:unsignedInt
long
xsd:unsignedShort
int
xsd:unsignedByte
short
xsd:unsignedLong
java.math.BigDecimal
xsd:time
javax.xml.datatype.XMLGregorianCalendar
xsd:date
javax.xml.datatype.XMLGregorianCalendar
xsd:g
javax.xml.datatype.XMLGregorianCalendar
xsd:anySimpleType
java.lang.Object
xsd:anySimpleType
java.lang.String
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"));
输出:


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  webservice cxf jaxb jaxws