使用Saaj调用WebService生成消息时,如果服务端的方法中的参数是List<?>的时候,或是参数是对象(javaBean)但是对象中包含List的时候,小弟我就不知道用SAAJ生成消息时该如何处理了~!比如:
服务端的接口package com.why.server;   
  
import javax.jws.WebParam;   
import javax.jws.WebService;   
import javax.jws.soap.SOAPBinding;   
import javax.xml.ws.soap.MTOM;   
  
/**  
 *   
 * @author why  
 *  
 */  
@WebService(name="Hello")   
@SOAPBinding(style = SOAPBinding.Style.RPC)   
public interface Hello {   
    public void printContext();     //实现方法1 
    public Customer selectMaxAgeCustomer(Customer c1, Customer c2);   //实现方法2
    
    public Customer receiveCustomerData(Customer[] c);   //无解方法1
    public Customer receiveCustomerListData(CustomerList c);   // 无解方法2
}  实现类:package com.why.server;   
  
import java.io.File;   
import java.io.FileOutputStream;   
import java.io.IOException;   
import java.io.InputStream;   
import java.io.OutputStream;   
import java.text.ParseException;   
import java.text.SimpleDateFormat;   
import java.util.Date;   
import java.util.Set;   
import javax.activation.DataHandler;   
import javax.activation.FileDataSource;   
import javax.annotation.Resource;   
import javax.jws.WebService;   
import javax.xml.ws.WebServiceContext;   
import javax.xml.ws.handler.MessageContext;   
import javax.xml.ws.soap.MTOM;   
  
/**  
 *   
 * 通过@MTOM注解启动MTOM传输方式,使用CXF实现时,这个注解放在接口或者实现类上都可以,使用JDK1.6自带实现时,需标注在实现类上  
 * @author why  
 *  
 */  
@WebService(serviceName="HelloService",portName="HelloServicePort",targetNamespace="http://service.why.com/",endpointInterface="com.why.server.Hello")   
@MTOM  
public class HelloImpl implements Hello {
     @Resource  
     private WebServiceContext context; 
   
     public void printContext(){
        MessageContext ctx = context.getMessageContext();   
        Set<String> set = ctx.keySet();   
        for (String key : set) {   
            System.out.println("{" + key + "," + ctx.get(key) +"}");   
            try {   
                System.out.println("key.scope=" + ctx.getScope(key));   
            } catch (Exception e) {   
                System.out.println(key + " is not exits");   
            }   
        }   
     }  
    
    @Override  
    public Customer selectMaxAgeCustomer(Customer c1, Customer c2) {   
        try {   
            // 输出接收到的附件   
            System.out.println("c1.getImageData().getContentType()=" + c1.getImageData().getContentType());   
            InputStream is = c1.getImageData().getInputStream();   
            OutputStream os = new FileOutputStream("c:\\temp1.jpg");   
            byte[] bytes = new byte[1024];   
            int c;   
            while ((c = is.read(bytes)) != -1) {   
                os.write(bytes, 0, c);   
            }   
            os.close();   
               
            System.out.println("c2.getImageData().getContentType()=" + c2.getImageData().getContentType());   
            is = c2.getImageData().getInputStream();   
            os = new FileOutputStream("c:\\temp2.jpg");   
            bytes = new byte[1024];   
            while ((c = is.read(bytes)) != -1) {   
                os.write(bytes, 0, c);   
            }   
            os.close();   
        } catch (IOException e) {   
            e.printStackTrace();   
        }   
           
        if (c1.getBirthday().getTime() > c2.getBirthday().getTime()){   
            return c2;   
        }   
        else{   
            return c1;   
        }   
    }      @Override  
    public Customer receiveCustomerData(Customer[] c){   
        ... 
    }   
       
    @Override  
    public Customer receiveCustomerListData(CustomerList c) {   
         
        ... 
    }   

Customer类:package com.why.server;   
  
import java.util.Date;   
  
import javax.activation.DataHandler;   
import javax.xml.bind.annotation.XmlAccessType;   
import javax.xml.bind.annotation.XmlAccessorType;   
import javax.xml.bind.annotation.XmlMimeType;   
import javax.xml.bind.annotation.XmlRootElement;   
  
/**  
 *   
 * @author why  
 *  
 */  
@XmlRootElement(name = "Customer")   
@XmlAccessorType(XmlAccessType.FIELD)   
public class Customer {   
    private long id;   
    private String name;   
    private Date birthday;   
    @XmlMimeType("application/octet-stream")   
    private DataHandler imageData;      ...
}CustomerList 类:/**  
 *   
 * @author why  
 *  
 */  
@XmlRootElement(name = "CustomerList")   
@XmlAccessorType(XmlAccessType.FIELD)   
public class CustomerList {   
    List<Customer> customer;
    
    public List<Customer> get(){
        if(customer == null){
           customer = new ArrayList<Customer>();
        }
        return this.customer;
    }
     ...
}
发布代码:public class SoapServer {   
    public static void main(String[] args) {   
        Endpoint.publish("http://localhost:8080/helloService",new HelloImpl());   
  
    }   
}  

解决方案 »

  1.   

    客户端代码,我不是通过代码生成器生成的,而是自己用Saaj组织SOAP消息向服务器发送请求!
    /**  
     *   
     * @author why  
     *  
     */  
    public class SoapClient {   
        public static void main(String[] args) throws Exception{   
               
            printContext();   
        }   
           
        /**  
         * 调用一个无参函数  
         * @throws Exception  
         */  
        public static void printContext() throws Exception{   
            // 获取SOAP连接工厂   
            SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance();   
            // 从SOAP连接工厂创建SOAP连接对象   
            SOAPConnection connection = factory.createConnection();   
            // 获取消息工厂   
            MessageFactory mFactory = MessageFactory.newInstance();   
            // 从消息工厂创建SOAP消息对象   
            SOAPMessage message = mFactory.createMessage();   
            // 创建SOAPPart对象   
            SOAPPart part = message.getSOAPPart();   
            // 创建SOAP信封对象   
            SOAPEnvelope envelope = part.getEnvelope();   
            // 创建SOAPHeader对象   
            SOAPHeader header = message.getSOAPHeader();   
            // 创建SOAPBody对象   
            SOAPBody body = envelope.getBody();   
               
            // 创建XML的根元素   
            SOAPBodyElement bodyElementRoot = body.addBodyElement(new QName("http://server.why.com/", "printContext", "ns1"));   
               
            // 访问Web服务地址   
            SOAPMessage reMessage = connection.call(message, new URL("http://127.0.0.1:8080/helloService"));   
            // 控制台输出返回的SOAP消息   
            OutputStream os = System.out;   
            reMessage.writeTo(os);   
               
            connection.close();   
        }      /**  
         * 调用一个在soap:Body中传递参数的函数  
         * @throws Exception  
         */  
        public static void selectMaxAgeCustomer() throws Exception{   
            // 获取SOAP连接工厂   
            SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance();   
            // 从SOAP连接工厂创建SOAP连接对象   
            SOAPConnection connection = factory.createConnection();   
            // 获取消息工厂   
            MessageFactory mFactory = MessageFactory.newInstance();   
            // 从消息工厂创建SOAP消息对象   
            SOAPMessage message = mFactory.createMessage();   
            // 创建SOAPPart对象   
            SOAPPart part = message.getSOAPPart();   
            // 创建SOAP信封对象   
            SOAPEnvelope envelope = part.getEnvelope();   
            // 创建SOAPHeader对象   
            SOAPHeader header = message.getSOAPHeader();   
            // 创建SOAPBody对象   
            SOAPBody body = envelope.getBody();   
      
            // 设置Content-Type   
            MimeHeaders hd = message.getMimeHeaders();    
            hd.setHeader("Content-Type", "application/xop+xml; charset=utf-8; type=\"text/xml\"");   
      
            // 创建XML的根元素   
            SOAPBodyElement bodyElementRoot = body.addBodyElement(new QName("http://server.why.com/", "selectMaxAgeCustomer", "ns1"));   
               
            // 创建Customer实例1   
            SOAPElement elementC1 = bodyElementRoot.addChildElement(new QName("arg0"));   
            elementC1.addChildElement(new QName("id")).addTextNode("1");   
            elementC1.addChildElement(new QName("name")).addTextNode("A");   
            elementC1.addChildElement(new QName("birthday")).addTextNode("1989-01-28T00:00:00.000+08:00");   
            // 创建附件对象   
            AttachmentPart attachment = message.createAttachmentPart(new DataHandler(new FileDataSource("c:\\c1.jpg")));   
            // 设置Content-ID   
            attachment.setContentId("<" + UUID.randomUUID().toString() + ">");   
            attachment.setMimeHeader("Content-Transfer-Encoding", "binary");   
            message.addAttachmentPart(attachment);   
            SOAPElement elementData = elementC1.addChildElement(new QName("imageData"));   
               
            // 添加XOP支持   
            elementData.addChildElement(   
                    new QName("http://www.w3.org/2004/08/xop/include", "Include","xop"))   
                    .addAttribute(new QName("href"),"cid:" + attachment.getContentId().replaceAll("<", "").replaceAll(">", ""));   
               
            // 创建Customer实例2   
            SOAPElement elementC2 = bodyElementRoot.addChildElement(new QName("arg1"));   
            elementC2.addChildElement(new QName("id")).addTextNode("2");   
            elementC2.addChildElement(new QName("name")).addTextNode("B");   
            elementC2.addChildElement(new QName("birthday")).addTextNode("1990-01-28T00:00:00.000+08:00");   
            AttachmentPart attachment2 = message.createAttachmentPart(new DataHandler(new FileDataSource("c:\\c2.jpg")));   
            attachment2.setContentId("<" + UUID.randomUUID().toString() + ">");   
            message.addAttachmentPart(attachment2);   
            SOAPElement elementData2 = elementC2.addChildElement(new QName("imageData"));   
               
            elementData2.addChildElement(   
                    new QName("http://www.w3.org/2004/08/xop/include", "Include","xop"))   
                    .addAttribute(new QName("href"),"cid:" + attachment2.getContentId().replaceAll("<", "").replaceAll(">", ""));   
               
            // 控制台输出发送的SOAP消息   
            OutputStream os = new ByteArrayOutputStream();   
            message.writeTo(os);   
            String soapStr = os.toString();   
            System.out.println("\n@@@@@@@@@@@@@@@@@@\n"+soapStr+"\n@@@@@@@@@@@@@@@@@@");   
               
            // 访问Web服务地址   
            SOAPMessage reMessage = connection.call(message, new URL("http://127.0.0.1:8080/helloService"));   
            // 控制台输出返回的SOAP消息   
            OutputStream baos = new ByteArrayOutputStream();   
            reMessage.writeTo(baos);   
            String soapStr2 = baos.toString();   
            System.out.println("\n#############\n"+soapStr2+"\n################");   
               
    //      // 输出SOAP消息中的第一个子元素的元素名称   
            System.out.println("\n<<<<<<<<<<<<<<<<<<<" + reMessage.getSOAPBody().getFirstChild().getLocalName());   
            // 输出SOAP消息中的附件   
            Iterator<AttachmentPart> it = reMessage.getAttachments();   
            while (it.hasNext()) {   
                InputStream ins = it.next().getDataHandler().getInputStream();   
                byte[] b = new byte[ins.available()];   
                OutputStream ous = new FileOutputStream("c:\\bbb.jpg");   
                while (ins.read(b) != -1) {   
                    ous.write(b);   
                }   
                ous.close();   
            }   
               
            connection.close();   
               
        }
    其实我的问题就是把“实现方法2”中的参数变为对象数组或List对象集合,或是JavaBean中包含List对象数组,该如何在客户端代码中修改生成消息的代码?望赐教,不胜感激~~
      

  2.   

    我晕,就没人用过SAAJ这个东西吗?
      

  3.   

    好巧,楼主在我博客里问这个问题了吧,想搜点资料看有没有什么好的解决办法,搜到这来了,呵呵!
    我博客里回复你了,在这粘过来吧,没找到什么太好的解决办法,以下仅供参考:对于数组形式,查看wsdl文件可以看到,会被封装成类似这种方式:
    <xs:complexType name="customerArray" final="#all">
        <xs:sequence>
            <xs:element name="item" type="tns:customer" minOccurs="0" maxOccurs="unbounded" nillable="true"/>
        </xs:sequence>
    </xs:complexType>
    所以,在封装的时候,只要将其封装为
    <arg0>
        <item>
            <Customer>...</Customer>
        </item>
        <item>
            <Customer>...</Customer>
        </item>
        ...
    </arg0>
    这样的层次结构就可以了。对于集合,使用JDK自带的实现时,貌似不能直接传递,但可以变通一下:自定义一个bean,将要传递的list作为这个bean的属性就可以传递了,也就是说,对象内的list是可以传递的。
    public class CustomerList{
        private ArrayList list;
        //get and set method
    }
    不过我觉得应该尽量避免使用这种特定语言的内置对象。
    若使用其他实现,如CXF,可以直接传递,SOAP消息中封装方式与数组类似,不知道是JDK的BUG还是人家压根没考虑实现这种方式。
      

  4.   

    要是有什么好的解决办法,希望能到我那回复一下啊,怕找不到这个帖子了,呵呵,先谢了!回到这就行:
    http://wuhongyu.javaeye.com/blog/810571