Wie führe ich einen SOAP-Webdienstaufruf von einer Java-Klasse aus?

116

Ich bin relativ neu in der Welt der Webservices und meine Forschung scheint mich mehr verwirrt als aufgeklärt zu haben. Mein Problem ist, dass ich eine Bibliothek (jar) erhalten habe, die ich mit einigen Webservice-Funktionen erweitern muss.

Diese Bibliothek wird für andere Entwickler freigegeben, und unter den Klassen im JAR befinden sich Klassen mit einer Methode, die einen Webservice aufruft (der im Wesentlichen ein Attribut der Klasse festlegt, eine Geschäftslogik ausführt, z. B. das Speichern des Objekts in einer Datenbank). usw. und sendet das Objekt mit diesen Änderungen zurück). Ich möchte den Aufruf dieses Dienstes so einfach wie möglich gestalten, hoffentlich so einfach, dass der Entwickler, der die Klasse verwendet, dies nur tun muss.

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

Ich habe JAX-WS studiert, um es auf dem Server zu verwenden, aber es scheint mir, dass ich weder auf wsimportdem Server noch wsimportauf dem Client ein erstellen muss , da ich weiß, dass beide Klassen haben, brauche ich nur eine Interaktion zwischen Klassen sowohl auf dem Server als auch auf dem Client geteilt. Wie macht es Ihrer Meinung nach Sinn, den Webservice und den Aufruf in der Klasse durchzuführen?

jpz
quelle
Ihre Frage ist etwas unklar. Die Methode, die Sie erstellen möchten, (1) ruft das Objekt vom Webdienst ab. (2) ein wenig mit dem Objekt arbeiten; und (3) poste es zurück an den Webdienst. Ist es das?
acdcjunior
Nein, das Objekt wird im Client erstellt, es wird im Aufruf an das ws gesendet, das ws legt eine Variable fest, z. B. currentTime, führt eine Geschäftslogik aus, um es in einer Datenbank zu speichern, und sendet dann das Objekt zurück zum Client mit der aktuell eingestellten aktuellen Zeit. Hoffe ich habe mich ein bisschen besser erklärt. Danke dir.
JPZ

Antworten:

273

Ich verstehe, dass Ihr Problem darin besteht, einen SOAP-Webdienst (JAX-WS) von Java aus aufzurufen und sein zurückgegebenes Objekt abzurufen . In diesem Fall haben Sie zwei mögliche Ansätze:

  1. Generieren Sie die Java-Klassen durch wsimportund verwenden Sie sie. oder
  2. Erstellen Sie einen SOAP-Client, der:
    1. Serialisiert die Parameter des Dienstes in XML.
    2. Ruft die Webmethode über HTTP-Manipulation auf. und
    3. Analysieren Sie die zurückgegebene XML-Antwort zurück in ein Objekt.


Über den ersten Ansatz (mit wsimport):

Ich sehe, dass Sie bereits über die Geschäftsklassen der Services (Entitäten oder andere) verfügen, und es ist eine Tatsache, dass die wsimporteine ganze Reihe neuer Klassen generiert (die irgendwie Duplikate der Klassen sind, die Sie bereits haben).

Ich fürchte jedoch, in diesem Szenario können Sie nur eines von beiden:

  • Passen Sie den wsimportgenerierten Code an (bearbeiten Sie ihn) , damit er Ihre Geschäftsklassen verwendet (dies ist schwierig und irgendwie nicht wert - denken Sie daran, dass Sie den Code jedes Mal neu generieren und anpassen müssen, wenn sich die WSDL ändert). oder
  • Gib auf und benutze die wsimportgenerierten Klassen. (In dieser Lösung könnte Ihr Geschäftscode die generierten Klassen als Service von einer anderen Architekturebene "verwenden".)

Informationen zum zweiten Ansatz (Erstellen Sie Ihren benutzerdefinierten SOAP-Client):

Um den zweiten Ansatz zu implementieren, müssen Sie:

  1. Rufen Sie an:
    • Verwenden Sie das SAAJ-Framework (SOAP mit Attachments API für Java) (siehe unten, es wird mit Java SE 1.6 oder höher geliefert), um die Anrufe zu tätigen. oder
    • Sie können es auch durch java.net.HttpUrlconnection(und einige java.ioHandhabung) tun .
  2. Verwandeln Sie die Objekte in und aus XML:
    • Verwenden Sie ein OXM-Framework (Object to XML Mapping) wie JAXB, um das XML von / in Objekte zu serialisieren / deserialisieren
    • Wenn nötig, erstellen / analysieren Sie das XML manuell (dies kann die beste Lösung sein, wenn sich das empfangene Objekt nur geringfügig vom gesendeten unterscheidet).

Das Erstellen eines SOAP-Clients mit classic java.net.HttpUrlConnectionist nicht so schwierig (aber auch nicht so einfach), und Sie finden in diesem Link einen sehr guten Startcode.

Ich empfehle Ihnen, das SAAJ-Framework zu verwenden:

Die API für SOAP mit Anhängen für Java (SAAJ) wird hauptsächlich für den direkten Umgang mit SOAP-Anforderungs- / Antwortnachrichten verwendet, die in einer Webdienst-API hinter den Kulissen auftreten. Es ermöglicht den Entwicklern, Seifennachrichten direkt zu senden und zu empfangen, anstatt JAX-WS zu verwenden.

Unten sehen Sie ein funktionierendes Beispiel (führen Sie es aus!) Eines SOAP-Webdienstaufrufs mit SAAJ. Es ruft diesen Webdienst auf .

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;
    }

}

Informationen zur Verwendung von JAXB zum Serialisieren / Deserialisieren sind sehr einfach zu finden. Sie können hier beginnen: http://www.mkyong.com/java/jaxb-hello-world-example/ .

acdcjunior
quelle
Wie stelle ich die Seifenversion mit der oben genannten Methode ein?
Erneuert
Ich konnte Ihre Methode verwenden und es hat funktioniert, als ich Ihren URI verwendet habe, aber für meine eigene SOAP-Anfrage erhalte ich eine Antwort, bei der keiner der Werte wie erwartet angezeigt wird, d <xsd:element name="Incident_Number" type="xsd:string"/>. H. Wie Sie sehen können, ist das Element geschlossen und es werden keine Informationen vom WS generiert.
Martin Erlic
Das GetInfoByCityist 503Service Unavailable, es scheint. :(
Brad Turek
@BradTurek D * mn! Ich habe es gerade ersetzt. Danke für die Information! Ich werde einen anderen finden und gleich darauf umsteigen.
Acdcjunior
1
An den Passanten: Wenn der obige Code (der Beispiel-SOAP-Webdienst-Endpunkt) nicht mehr funktioniert oder Fehler (wie 500, 503 usw.) verursacht, lassen Sie es mich bitte wissen, damit ich ihn beheben kann.
Acdcjunior
3

Oder verwenden Sie einfach wsdl2java von Apache CXF , um Objekte zu generieren, die Sie verwenden können.

Es ist in dem Binärpaket enthalten, das Sie von der Website herunterladen können. Sie können einfach einen Befehl wie folgt ausführen:

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

Es nutzt die WSDL - Datei Objekte zu erzeugen, die Sie wie können diese (Objektnamen werden ebenfalls aus der WSDL - Datei gepackt, so deine anders ein wenig sein wird):

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

Es gibt sogar ein Maven-Plug-In, das die Quellen generiert: https://cxf.apache.org/docs/maven-cxf-codegen-plugin-wsdl-to-java.html

Hinweis: Wenn Sie Quellen mit CXF und IDEA generieren, sollten Sie sich Folgendes ansehen: https://stackoverflow.com/a/46812593/840315

szab.kel
quelle
1
Ich habe 30+ wsdl in meiner Anwendung. Während ich Ressourcen für nur 1 wsdl vorbereitete (mit 5 soapActions), hing meine Eclipse-IDE und generierte mehr als 100 MB Klassen / Objekte.
Manmohan_singh
-1

Ich habe eine viel einfachere Alternative zum Generieren von Seifenmeldungen gefunden. Gegeben ein Personenobjekt:

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
}

Unten finden Sie einen einfachen Soap Message Generator:

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);
  }
}

Sie können verwenden durch:

 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);
      }
mel3kings
quelle