在SOAP中方法的参数是有流向的,@WebParam注解的mode属性由javax.jws.WebParam.Mode枚举指定,表示参数的流向,默认是IN,也就是输入参数,还可以是OUT,INOUT类型。
如果是OUT或INOUT类型的类型参数,这样的方法参数将会被当作返回值在Web服务调用完成后返回给你,客户端生成代码时会被转变为javax.xml.ws.Holder<T>类型, 注意不要导错包,不是javax.sml.rpc.Holder类型,Holder是一个泛型类,他持有类型T。
举例:
服务端SEI:
package com.test.inter.service;
import javax.jws.WebParam;
import javax.jws.WebParam.Mode;
import javax.jws.WebService;
import javax.xml.ws.Holder;
import com.test.bean.Customer;
@WebService
public interface IHelloService2 {
public boolean selectMaxAgeCustomer(@WebParam(name = "c1") Customer c1,
@WebParam(name = "c2") Customer c2,
@WebParam(name = "c3", mode = Mode.OUT) Holder<Customer> c3);
public void selectLongNameCustomer(@WebParam(name = "c1") Customer c1,
@WebParam(name = "c2") Customer c2,
@WebParam(name = "c3", mode = Mode.OUT) Holder<Customer> c3);
}
服务端SEI具体实现类:
package com.test.impl.service;
import javax.xml.ws.Holder;
import com.test.bean.Customer;
import com.test.inter.service.IHelloService2;
public class HelloServiceImpl2 implements IHelloService2{
@Override
public boolean selectMaxAgeCustomer(Customer c1, Customer c2,
Holder<Customer> c3) {
if(c1 == null || c2 == null){
return false;
}
if(c1.getBirthday().getMillisecond() > c1.getBirthday().getMillisecond()){
c3.value = c2;
}else{
c3.value = c1;
}
return true;
}
@Override
public void selectLongNameCustomer(Customer c1, Customer c2,
Holder<Customer> c3) {
if(c1 != null && c2 != null){
if(c1.getName().length() < c2.getName().length()){
c3.value = c2;
}else{
c3.value = c1;
}
}
}
}
客户端调用代码:
package com.test.client;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;
import javax.xml.ws.Holder;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import com.sun.org.apache.xerces.internal.jaxp.datatype.XMLGregorianCalendarImpl;
import com.test.bean.Customer;
import com.test.inter.service.IHelloService;
import com.test.inter.service.IHelloService2;
public class SoapClient2 {
public static void main(String[] args) throws ParseException {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setAddress("http://localhost:8080/helloService");
factory.setServiceClass(IHelloService2.class);
Object o = factory.create();
IHelloService2 service = (IHelloService2)o;
Customer c1 = new Customer();
c1.setId(1L);
c1.setName("A");
GregorianCalendar calendar = (GregorianCalendar) GregorianCalendar.getInstance();
calendar.setTime(new SimpleDateFormat("yyyy-MM-dd").parse("1993-03-06"));
c1.setBirthday(new XMLGregorianCalendarImpl(calendar));
Customer c2 = new Customer();
c2.setId(2L);
c2.setName("AB");
calendar.setTime(new SimpleDateFormat("yyyy-MM-dd").parse("1993-04-06"));
c2.setBirthday(new XMLGregorianCalendarImpl(calendar));
Holder<Customer> c3 = new Holder<Customer>();
service.selectMaxAgeCustomer(c1, c2, c3 );
System.out.println(c3.value.getName());
service.selectLongNameCustomer(c1, c2, c3);
System.out.println(c3.value.getName());
}
}
输出结果:
从上面的代码不难看出,不管你的方法是否有返回值,c3中都能够输出运行结果,因此,当你的方法参数mode属性设置为Mode.OUT,不过你的方法有无返回值,都能够从Holder<T>中取得结果。
@javax.jws.OneWay注解是一个标示性注解,没有任何属性,它表示公开的Web服务的方法没有任何的返回值,不允许有OUT类型的参数,不允许抛出非运行时异常。如果条件不符合JAX-WS规范要求应该报告错误,但是CXF的策略是如果方法存在返回值,生成客户端时将被改为void,如果方法参数含有OUT类型,生成客户端时将会被忽略,如果方法参数含有INOUT类型,生成客户端时将只作为IN类型参数被保留。
举例:
服务器SEI:
package com.test.inter.service;
import javax.jws.Oneway;
import javax.jws.WebParam;
import javax.jws.WebParam.Mode;
import javax.jws.WebService;
import javax.xml.ws.Holder;
import com.test.bean.Customer;
@WebService
public interface IHelloService3 {
@Oneway
public boolean selectMaxAgeCustomer(@WebParam(name = "c1") Customer c1,
@WebParam(name = "c2") Customer c2,
@WebParam(name = "c3", mode = Mode.OUT) Holder<Customer> c3);
public void selectLongNameCustomer(@WebParam(name = "c1") Customer c1,
@WebParam(name = "c2") Customer c2,
@WebParam(name = "c3", mode = Mode.OUT) Holder<Customer> c3);
}
以下执行结果是采用代理工厂调用Web服务的方式
执行结果,将会抛出异常:
Caused by: java.lang.IllegalArgumentException: wrong number of arguments
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:181)
at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:97)
... 17 more
参数个数错误,原因是@OneWay注解标注的方法是没有返回值的,因此,selectMaxAgeCustomer方法需要三个输入参数,而我们实际定义的是两个输入参数,一个输出参数。