java创建webservice client

本文介绍了如何在Java中创建WebService客户端,特别是使用SOAPConnection调用服务并处理返回结果的过程。涉及SOAPMessage的封装,包括利用JAXB将对象转换为XML,处理XML的命名空间和前缀,以及处理UTF-8 BOM问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java的webservice实现有多种方式,可用的工具也有一些。之前对这块的只是比较缺乏,以至于一上来就一直看spring webservice.花费了几天后发现和要用的功能不符,就···

当前学习的需求是webservice client。因此整篇文章用来说明java webserviceclient的创建过程。

首先使用java自带的soapconnection实现。那首先具体的client访问流程为

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

SOAPConnection connection = null;

 

        try {

            SOAPConnectionFactory sfc = SOAPConnectionFactory.newInstance();

            connection = sfc.createConnection();

            SOAPMessage soapMessage = ObjectToSoapXml(object, nsMethod, nsName);

 

            URL endpoint = new URL(new URL(url),

                    "",

                    new URLStreamHandler() {

                        @Override

                        protected URLConnection openConnection(URL url) throws IOException {

                            URL target = new URL(url.toString());

                            URLConnection connection = target.openConnection();

                            // Connection settings

                            connection.setConnectTimeout(120000); // 2 min

                            connection.setReadTimeout(60000); // 1 min

                            return(connection);

                        }

                    });

 

            SOAPMessage response = connection.call(soapMessage, endpoint);

             

        catch (Exception e) {

             

        }

 这其中首先创建soapconnection调用call方法向server端发送请求,call的两个参数一个是发送的消息soapmessage,一个是服务器端地址。

那这里的关键是soapmessage的封装,那在java中,信息一般采用对象的形式存储。问题就是怎样把含有信息的对象封装成soapMessage.我采用的方法是

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

private static<T> SOAPMessage ObjectToSoapXml(T object, String nsMethod, String nsName) {

        SOAPMessage soapMessage = null;

 

        try {

            MessageFactory messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);

            soapMessage = messageFactory.createMessage();

            SOAPPart soapPart = soapMessage.getSOAPPart();

            // SOAP Envelope

            SOAPEnvelope envelope = soapPart.getEnvelope();

            envelope.setPrefix("SOAP-ENV");

            envelope.addNamespaceDeclaration("ns1", nsMethod);

 

            // SOAP Body

            SOAPBody soapBody = envelope.getBody();

            soapBody.setPrefix("SOAP-ENV");

 

            soapBody.addDocument(jaxbObjectToXML(object, nsMethod, nsName));//将body中的类通过document的形式写入

            soapMessage.saveChanges();

        catch (SOAPException e) {

            e.printStackTrace();

             

        }

 

        return soapMessage;

    }

  使用messagefactory创建soapmessage,这里有一点要注意SOAPConstants.SOAP_1_1_PROTOCOL,使用这个参数的原因是要指定soapmessage的content-type为text/xml,charset=utf-8,那其他的可再参考其他常量。那创建的soapmessage就包含soapenvelop了,可添加前缀和命名空间。接下来就是在soapbody中添加要传递的信息对象。一开始看到的各种例子都是一个元素一个元素的添加。可扩展性太差了。一直考虑将整个对象添加进去。采用方式是soapbody adddocument的方式。那就要把信息对象转换成org.w3c.dom.Document对象。接下来是转换方式

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

private static<T> Document jaxbObjectToXML(T emp, String nsMethod, String nsName) {

        try {

            JAXBContext context = JAXBContext.newInstance(emp.getClass());

            // Create the Document

            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

            DocumentBuilder db = dbf.newDocumentBuilder();

            Document document = db.newDocument();

 

            // Marshal the Object to a Document

            Marshaller marshaller = context.createMarshaller();

            marshaller.marshal(emp, document);

            if(null != document) {

                document.renameNode(document.getFirstChild(), nsMethod, nsName);

            }

 

            return document;

        catch (Exception e) {

            logger.error(e.toString(), e);

        }

        return null;

    }

  使用jaxb将object转成xml,marshal方法可直接实现对象到document。我在这里遇到的一个问题是,对象到xml的时候,我的xml要求根元素有前缀。没知识实在不好添加。最终找到实现方式是转换成的document获取根元素,通过getfirstchild的方式,然后对根元素重命名 renameNode,这里的问题是这个方法的后两个参数一个是命名空间,一个是重命名后节点名称。我要使用的是含有前缀,无命名空间。其实这样说就是没知识了。前缀和命名空间应该是对应的,命名空间和前缀应一起设置。只是命名空间并不显示。若只设置前缀,无命名空间则会报错。那这里问题就愉快的解决了,此时是完成了对象封装成soapmessage,就可以通过soapconnection向服务端发消息了。

那消息发送出去服务端返回结果是不是还要处理一下呢?当然可以通过元素逐级获取的方式获取你要的元素。同样扩展性太差。我采用的方式同样是把soapbody中的内容实现到对象的对应。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

public static<T> T parseSoapMessage(SOAPMessage reqMsg, T object, String name) {

        try {

            reqMsg = removeUTFBOM(reqMsg);

            SOAPBody soapBody = reqMsg.getSOAPBody();

            Document document = soapBody.extractContentAsDocument();//获取返回信息中的消息体

            document.renameNode(document.getFirstChild(), null, name);//根节点去掉前缀

            JAXBContext jc = JAXBContext.newInstance(object.getClass());

            Unmarshaller unmarshaller = jc.createUnmarshaller();

            object = (T)unmarshaller.unmarshal(document);

        }catch(Exception e) {

            logger.error(e.toString(), e);

        }

 

        return object;

    }

  

大问题来了,调用soapconnection返回的soapmessage,直接调用getsoapbody报错了。几番查看,是返回的结果是utf-8 BOM滴,额,这个处理没有找到好的方式。最终也只是将soapmessage转成string将BOM去掉之后再转换回来。因之前对象到soapmessage转换时使用document,那现在也考虑这种方式并且可行了。那注意抽取出来的document呢我这边还是含有前缀的,所以使用renameNode做了一下去除前缀的处理,然后使用unmarshal将document嗨皮的转成对象了。终于完成了。

去BOM的方式

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

private static SOAPMessage removeUTFBOM(SOAPMessage soapMessage) {

        ByteArrayOutputStream baos = null;

        try

        {

            baos = new ByteArrayOutputStream();

            soapMessage.writeTo(baos);

            String soapString = baos.toString();

            if (baos.toString().startsWith("\uFEFF")) {

                soapString = soapString.substring(1);

                InputStream is = new ByteArrayInputStream(soapString.getBytes());

                soapMessage = MessageFactory.newInstance().createMessage(null, is);

            }

 

        catch (SOAPException e) {

            logger.error(e.toString(), e);

        catch (IOException e) {

            logger.error(e.toString(), e);

        }

 

        return soapMessage;

    }

  最后还有一点就是xml对应bean的定义

我采取的方式是在类上注解

@XmlRootElement(name = "name") //声明为根元素,根元素名字
@XmlAccessorType(XmlAccessType.FIELD)

然后在各个元素上

@XmlElement(name = "elementname", nillable = true)

指定该属性对应xml中元素的名字,使用nillable属性是因为,若此属性为空的话,相应的xml元素便不存在,指定此属性为true,则为空的属性也会显示。

再就是为根元素的类中含有其他对象时,其他对象的声明方式

首先在类上声明   @XmlAccessorType(XmlAccessType.FIELD)

相应属性上声明      @XmlElement(name = "elementname", nillable = true)

再就是有些属性为list

@XmlElementWrapper(name="ListName")
@XmlElement(name="ListelementName", nillable = true)

wrapper指定list的名字,接下来指定list中各个元素的名字。

呼~ 终于走完了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值