Java sınıfından SOAP Web Servisi araması nasıl yapılır?


116

Web hizmetleri dünyasında görece yeniyim ve araştırmalarım beni aydınlatmaktan daha çok kafamı karıştırmış gibi görünüyor, benim sorunum, bazı web hizmeti işlevleriyle genişletmem gereken bir kitaplık (kavanoz) verilmiş olması.

Bu kitaplık diğer geliştiricilerle paylaşılacak ve kavanozdaki sınıflar arasında bir web hizmetini çağıran bir yönteme sahip olan sınıflar olacaktır (esasen sınıfın bir özniteliğini belirleyen, nesneyi bir veritabanında depolamak gibi bazı iş mantığını yapan, vb ve bu değişikliklerle nesneyi geri gönderir). Bu hizmete yapılan çağrıyı olabildiğince basit hale getirmek istiyorum, umarım o kadar basit ki, sınıfı kullanan geliştiricinin yapması gereken tek şey.

Car c = new Car("Blue");
c.webmethod();

Sunucuda kullanmak için JAX-WS üzerinde çalışıyorum, ancak bana wsimportsunucuda veya wsimportistemcide bir oluşturmam gerekmiyor gibi görünüyor , çünkü her ikisinin de sınıfları olduğunu biliyorum, sadece sınıflar arasında biraz etkileşime ihtiyacım var hem sunucuda hem de istemcide paylaşılır. Web hizmetini ve aramayı sınıfta yapmanın ne kadar mantıklı olduğunu düşünüyorsunuz?


Sorunuz biraz belirsiz. Oluşturmak istediğiniz yöntem (1) nesneyi web hizmetinden alır; (2) nesneyle biraz çalışın; ve (3) web hizmetine geri gönderin. Öyle mi?
acdcjunior

Hayır, nesne istemcide oluşturulacak, çağrıda ws'ye gönderilecek, ws bir değişken ayarlayacak, örneğin currentTime, bir db'de saklamak gibi bazı iş mantığı yapacak ve sonra nesneyi gönderecek Şimdi ayarlanmış currentTime ile istemciye geri dönün. Umarım kendimi biraz daha iyi anlatmışımdır. Teşekkür ederim.
jpz

Yanıtlar:


273

Probleminizin Java'dan bir SOAP (JAX-WS) web servisini nasıl çağıracağınıza ve geri dönen nesneyi nasıl alacağınıza bağlı olduğunu anlıyorum . Bu durumda, iki olası yaklaşımınız vardır:

  1. Java sınıflarını oluşturun wsimportve kullanın; veya
  2. Şu özelliklere sahip bir SOAP istemcisi oluşturun:
    1. Hizmetin parametrelerini XML'e serileştirir;
    2. HTTP işlemiyle web yöntemini çağırır; ve
    3. Dönen XML yanıtını bir nesneye geri ayrıştırın.


İlk yaklaşım hakkında (kullanarak wsimport):

Zaten hizmetlerin (varlıklar veya diğer) işletme sınıflarına sahip olduğunuzu görüyorum ve bu, wsimporttamamen yeni bir sınıflar kümesi oluşturduğu bir gerçektir (bunlar zaten sahip olduğunuz sınıfların bir şekilde kopyalarıdır).

Korkarım ki bu senaryoda sadece şunlardan birini yapabilirsiniz:

  • wsimportOluşturulan kodu iş sınıflarınızı kullanacak şekilde uyarlayın (düzenleyin) (bu zordur ve bir şekilde buna değmez - WSDL her değiştiğinde kodu yeniden oluşturmanız ve yeniden ayarlamanız gerekeceğini unutmayın); veya
  • wsimportÜretilen sınıflardan vazgeçin ve kullanın . (Bu çözümde, iş kodunuz üretilen sınıfları başka bir mimari katmandan bir hizmet olarak "kullanabilir".)

İkinci yaklaşım hakkında (özel SOAP istemcinizi oluşturun):

İkinci yaklaşımı uygulamak için yapmanız gerekenler:

  1. Arama yap:
    • Çağrıları yapmak için SAAJ (Java için Eklentiler API'si ile SABUN) çerçevesini kullanın (aşağıya bakın, Java SE 1.6 veya üstü ile birlikte gelir); veya
    • Bunu da yapabilirsiniz java.net.HttpUrlconnection(ve bazı java.ioişlemlerle).
  2. Nesneleri XML'e ve XML'den geri dönüştürün:
    • XML'i nesnelerden / nesnelere seri hale getirmek / seri durumdan çıkarmak için JAXB gibi bir OXM (Nesneden XML Eşleştirmeye) çerçevesi kullanın
    • Veya gerekirse, XML'yi manuel olarak oluşturun / ayrıştırın (bu, alınan nesne gönderilenden biraz farklıysa en iyi çözüm olabilir).

Classic kullanarak bir SOAP istemcisi oluşturmak java.net.HttpUrlConnectiono kadar da zor değil (ama o kadar da basit değil) ve bu bağlantıda çok iyi bir başlangıç ​​kodu bulabilirsiniz.

SAAJ çerçevesini kullanmanızı tavsiye ederim:

Java için Eklentili SABUN (SAAJ) , esas olarak herhangi bir Web Hizmeti API'sinde perde arkasında gerçekleşen SOAP İstek / Yanıt mesajlarıyla doğrudan ilgilenmek için kullanılır. Geliştiricilerin JAX-WS kullanmak yerine doğrudan sabun mesajları gönderip almalarını sağlar.

SAAJ kullanarak bir SOAP web servis çağrısının çalışan bir örneğini (çalıştırın!) Aşağıya bakın. Bu web servisini çağırıyor .

import javax.xml.soap.*;

public class SOAPClientSAAJ {

    // SAAJ - SOAP Client Testing
    public static void main(String args[]) {
        /*
            The example below requests from the Web Service at:
             https://www.w3schools.com/xml/tempconvert.asmx?op=CelsiusToFahrenheit


            To call other WS, change the parameters below, which are:
             - the SOAP Endpoint URL (that is, where the service is responding from)
             - the SOAP Action

            Also change the contents of the method createSoapEnvelope() in this class. It constructs
             the inner part of the SOAP envelope that is actually sent.
         */
        String soapEndpointUrl = "https://www.w3schools.com/xml/tempconvert.asmx";
        String soapAction = "https://www.w3schools.com/xml/CelsiusToFahrenheit";

        callSoapWebService(soapEndpointUrl, soapAction);
    }

    private static void createSoapEnvelope(SOAPMessage soapMessage) throws SOAPException {
        SOAPPart soapPart = soapMessage.getSOAPPart();

        String myNamespace = "myNamespace";
        String myNamespaceURI = "https://www.w3schools.com/xml/";

        // SOAP Envelope
        SOAPEnvelope envelope = soapPart.getEnvelope();
        envelope.addNamespaceDeclaration(myNamespace, myNamespaceURI);

            /*
            Constructed SOAP Request Message:
            <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:myNamespace="https://www.w3schools.com/xml/">
                <SOAP-ENV:Header/>
                <SOAP-ENV:Body>
                    <myNamespace:CelsiusToFahrenheit>
                        <myNamespace:Celsius>100</myNamespace:Celsius>
                    </myNamespace:CelsiusToFahrenheit>
                </SOAP-ENV:Body>
            </SOAP-ENV:Envelope>
            */

        // SOAP Body
        SOAPBody soapBody = envelope.getBody();
        SOAPElement soapBodyElem = soapBody.addChildElement("CelsiusToFahrenheit", myNamespace);
        SOAPElement soapBodyElem1 = soapBodyElem.addChildElement("Celsius", myNamespace);
        soapBodyElem1.addTextNode("100");
    }

    private static void callSoapWebService(String soapEndpointUrl, String soapAction) {
        try {
            // Create SOAP Connection
            SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
            SOAPConnection soapConnection = soapConnectionFactory.createConnection();

            // Send SOAP Message to SOAP Server
            SOAPMessage soapResponse = soapConnection.call(createSOAPRequest(soapAction), soapEndpointUrl);

            // Print the SOAP Response
            System.out.println("Response SOAP Message:");
            soapResponse.writeTo(System.out);
            System.out.println();

            soapConnection.close();
        } catch (Exception e) {
            System.err.println("\nError occurred while sending SOAP Request to Server!\nMake sure you have the correct endpoint URL and SOAPAction!\n");
            e.printStackTrace();
        }
    }

    private static SOAPMessage createSOAPRequest(String soapAction) throws Exception {
        MessageFactory messageFactory = MessageFactory.newInstance();
        SOAPMessage soapMessage = messageFactory.createMessage();

        createSoapEnvelope(soapMessage);

        MimeHeaders headers = soapMessage.getMimeHeaders();
        headers.addHeader("SOAPAction", soapAction);

        soapMessage.saveChanges();

        /* Print the request message, just for debugging purposes */
        System.out.println("Request SOAP Message:");
        soapMessage.writeTo(System.out);
        System.out.println("\n");

        return soapMessage;
    }

}

JAXB'yi serileştirme / seriyi kaldırma için kullanma hakkında, onunla ilgili bilgileri bulmak çok kolaydır. Buradan başlayabilirsiniz: http://www.mkyong.com/java/jaxb-hello-world-example/ .


Yukarıda belirtilen yöntemi kullanarak sabun versiyonunu nasıl ayarlarım?
Redone

Yönteminizi kullanabildim ve URI'nizi kullandığımda işe yaradı, ancak kendi SOAP isteğim için hiçbir değerin beklendiği gibi gösterilmediği bir yanıt alıyorum, yani <xsd:element name="Incident_Number" type="xsd:string"/>. Gördüğünüz gibi, eleman kapalıdır ve WS'den herhangi bir bilgi üretilmez.
Martin Erlic

Bu GetInfoByCity, 503Service Unavailablegörünüyor. :(
Brad Turek

@BradTurek D * mn! Ben sadece bunu değiştirdi. Bilmeme izin verdiğin için teşekkürler! Başka bir tane bulup biraz sonra değiştireceğim.
acdcjunior

1
Yoldan geçen kişiye: Yukarıdaki kod (örnek SOAP Web Hizmeti uç noktası) çalışmayı durdurursa veya hatalar vermeye başlarsa (500, 503 vb. Gibi), düzeltebilmem için lütfen bana bildirin.
acdcjunior

3

Veya kullanabileceğiniz nesneler oluşturmak için Apache CXF'nin wsdl2java'sını kullanın.

Web sitelerinden indirebileceğiniz ikili pakete dahildir. Bunun gibi bir komut çalıştırabilirsiniz:

$ ./wsdl2java -p com.mynamespace.for.the.api.objects -autoNameResolution http://www.someurl.com/DefaultWebService?wsdl

Bu gibi kullanabileceğiniz, nesneleri oluşturmak için wsdl kullanan bu (sizin farklı bir az şey olacak, böylece nesne isimleri de, wsdl yakaladı edilir):

DefaultWebService defaultWebService = new DefaultWebService();
String res = defaultWebService.getDefaultWebServiceHttpSoap11Endpoint().login("webservice","dadsadasdasd");
System.out.println(res);

Kaynakları oluşturan bir Maven eklentisi bile var: https://cxf.apache.org/docs/maven-cxf-codegen-plugin-wsdl-to-java.html

Not: CXF ve IDEA kullanarak kaynaklar oluşturuyorsanız, şuna bakmak isteyebilirsiniz: https://stackoverflow.com/a/46812593/840315


1
Başvurumda 30+ wsdl var. Sadece 1 wsdl (5 soapActions'a sahip) için kaynak hazırlarken, Eclipse IDE'm takıldı ve yaklaşık 100+ MB sınıf / nesne oluşturdu.
Manmohan_singh

-1

Sabun mesajı oluşturmanın çok daha basit bir alternatifini buldum. Bir Kişi Nesnesi Verildiğinde:

import com.fasterxml.jackson.annotation.JsonInclude;

@JsonInclude(JsonInclude.Include.NON_NULL)
public class Person {
  private String name;
  private int age;
  private String address; //setter and getters below
}

Aşağıda basit bir Sabun Mesajı Oluşturucu:

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;

@Slf4j
public class SoapGenerator {

  protected static final ObjectMapper XML_MAPPER = new XmlMapper()
      .enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)
      .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
      .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
      .registerModule(new JavaTimeModule());

  private static final String SOAP_BODY_OPEN = "<soap:Body>";
  private static final String SOAP_BODY_CLOSE = "</soap:Body>";
  private static final String SOAP_ENVELOPE_OPEN = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">";
  private static final String SOAP_ENVELOPE_CLOSE = "</soap:Envelope>";

  public static String soapWrap(String xml) {
    return SOAP_ENVELOPE_OPEN + SOAP_BODY_OPEN + xml + SOAP_BODY_CLOSE + SOAP_ENVELOPE_CLOSE;
  }

  public static String soapUnwrap(String xml) {
    return StringUtils.substringBetween(xml, SOAP_BODY_OPEN, SOAP_BODY_CLOSE);
  }
}

Şunları kullanabilirsiniz:

 public static void main(String[] args) throws Exception{
        Person p = new Person();
        p.setName("Test");
        p.setAge(12);

        String xml = SoapGenerator.soapWrap(XML_MAPPER.writeValueAsString(p));
        log.info("Generated String");
        log.info(xml);
      }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.