Bagaimana cara melakukan panggilan SOAP Web Service dari kelas Java?

116

Saya relatif baru di dunia webservices dan penelitian saya tampaknya lebih membingungkan saya daripada mencerahkan saya, masalah saya adalah saya diberi perpustakaan (jar) yang harus saya kembangkan dengan beberapa fungsi webservice.

Library ini akan dibagikan ke developer lain, dan di antara class di jar akan ada class yang memiliki metode yang memanggil webservice (yang pada dasarnya menyetel atribut class, melakukan logika bisnis, seperti menyimpan objek dalam db, dll dan mengirimkan kembali objek dengan modifikasi tersebut). Saya ingin membuat panggilan ke layanan ini sesederhana mungkin, semoga sesederhana mungkin sehingga pengembang yang menggunakan kelas hanya perlu melakukannya.

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

Saya telah mempelajari JAX-WS untuk digunakan di server tetapi menurut saya saya tidak perlu membuat wsimportdi server maupun wsimportdi klien, karena saya tahu bahwa keduanya memiliki kelas, saya hanya perlu beberapa interaksi antar kelas dibagikan di server dan klien. Menurut Anda, bagaimana masuk akal untuk melakukan layanan web dan panggilan di kelas?

jpz
sumber
Pertanyaan Anda agak tidak jelas. Metode yang ingin Anda buat akan (1) mendapatkan objek dari layanan web; (2) mengerjakan sedikit objek; dan (3) mempostingnya kembali ke layanan web. Itu saja?
acdcjunior
Tidak, objek akan dibuat di klien, itu akan dikirim ke ws dalam panggilan, ws akan menetapkan variabel, misalnya currentTime, melakukan beberapa logika bisnis seperti menyimpannya dalam db, dan kemudian mengirim objek kembali ke klien dengan currentTime sekarang disetel. Harap saya menjelaskan diri saya sedikit lebih baik. Terima kasih.
jpz

Jawaban:

273

Saya memahami masalah Anda bermuara pada bagaimana memanggil layanan web SOAP (JAX-WS) dari Java dan mendapatkan objeknya kembali . Dalam hal ini, Anda memiliki dua kemungkinan pendekatan:

  1. Hasilkan kelas-kelas Java melalui wsimportdan gunakan mereka; atau
  2. Buat klien SOAP yang:
    1. Menyerialisasikan parameter layanan ke XML;
    2. Memanggil metode web melalui manipulasi HTTP; dan
    3. Parsing respons XML yang kembali menjadi objek.


Tentang pendekatan pertama (menggunakan wsimport):

Saya melihat Anda sudah memiliki kelas bisnis layanan (entitas atau lainnya), dan itu adalah fakta bahwa wsimportmenghasilkan serangkaian kelas yang sama sekali baru (yang entah bagaimana merupakan duplikat dari kelas yang sudah Anda miliki).

Saya khawatir, dalam skenario ini, Anda hanya dapat:

  • Sesuaikan (edit) wsimportkode yang dihasilkan untuk membuatnya menggunakan kelas bisnis Anda (ini sulit dan entah bagaimana tidak sepadan - ingatlah setiap kali WSDL berubah, Anda harus membuat ulang dan menyesuaikan kembali kode tersebut); atau
  • Menyerah dan menggunakan wsimportkelas yang dihasilkan. (Dalam solusi ini, kode bisnis Anda dapat "menggunakan" kelas yang dihasilkan sebagai layanan dari lapisan arsitektur lain.)

Tentang pendekatan kedua (buat klien SOAP kustom Anda):

Untuk menerapkan pendekatan kedua, Anda harus:

  1. Lakukan panggilan:
    • Gunakan kerangka kerja SAAJ (SOAP dengan Lampiran API untuk Java) (lihat di bawah, dikirimkan dengan Java SE 1.6 atau lebih tinggi) untuk melakukan panggilan; atau
    • Anda juga dapat melakukannya melalui java.net.HttpUrlconnection(dan beberapa java.iopenanganan).
  2. Ubah objek menjadi dan kembali dari XML:
    • Gunakan kerangka kerja OXM (Object to XML Mapping) seperti JAXB untuk membuat serial / deserialisasi XML dari / menjadi objek
    • Atau, jika Anda harus, buat / parsing XML secara manual (ini bisa menjadi solusi terbaik jika objek yang diterima hanya sedikit berbeda dari yang dikirim).

Membuat klien SOAP menggunakan klasik java.net.HttpUrlConnectiontidaklah sulit (tetapi juga tidak sesederhana itu), dan Anda dapat menemukan di tautan ini kode awal yang sangat baik.

Saya sarankan Anda menggunakan kerangka SAAJ:

SOAP dengan Attachments API for Java (SAAJ) terutama digunakan untuk menangani langsung dengan pesan SOAP Request / Response yang terjadi di balik layar dalam Web Service API. Ini memungkinkan pengembang untuk langsung mengirim dan menerima pesan sabun daripada menggunakan JAX-WS.

Lihat di bawah ini contoh kerja (jalankan!) Dari panggilan layanan web SOAP menggunakan SAAJ. Itu menyebut layanan web ini .

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

}

Tentang penggunaan JAXB untuk serialisasi / deserialisasi, sangat mudah untuk menemukan informasi tentangnya. Anda dapat mulai di sini: http://www.mkyong.com/java/jaxb-hello-world-example/ .

acdcjunior.dll
sumber
Bagaimana cara mengatur versi sabun menggunakan metode yang disebutkan di atas?
Ulangi
Saya dapat menggunakan metode Anda dan berhasil ketika saya menggunakan URI Anda tetapi untuk permintaan SOAP saya sendiri, saya mendapatkan respons dimana tidak ada nilai yang ditampilkan seperti yang diharapkan, yaitu <xsd:element name="Incident_Number" type="xsd:string"/>. Seperti yang Anda lihat, elemen ditutup dan tidak ada informasi yang dihasilkan dari WS.
Martin Erlic
The GetInfoByCityadalah 503Service Unavailable, itu seeems. :(
Brad Turek
@BradTurek D * mn! Saya baru saja menggantinya. Terima kasih telah memberi tahu saya! Saya akan menemukan yang lain dan mengubahnya sebentar lagi.
acdcjunior
1
Kepada orang yang lewat: Jika kode di atas (contoh titik akhir SOAP Web Service) berhenti berfungsi atau mulai memberikan kesalahan (seperti 500, 503, dll), beri tahu saya agar saya dapat memperbaikinya.
acdcjunior
3

Atau cukup gunakan wsdl2java Apache CXF untuk menghasilkan objek yang dapat Anda gunakan.

Itu termasuk dalam paket biner yang dapat Anda unduh dari situs web mereka. Anda cukup menjalankan perintah seperti ini:

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

Ini menggunakan wsdl untuk menghasilkan objek, yang dapat Anda gunakan seperti ini (nama objek juga diambil dari wsdl, jadi milik Anda akan sedikit berbeda):

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

Bahkan ada plug-in Maven yang menghasilkan sumber: https://cxf.apache.org/docs/maven-cxf-codegen-plugin-wsdl-to-java.html

Catatan: Jika Anda membuat sumber menggunakan CXF dan IDEA, Anda mungkin ingin melihat ini: https://stackoverflow.com/a/46812593/840315

szab.kel
sumber
1
Saya memiliki 30+ wsdl dalam aplikasi saya. Saat menyiapkan sumber daya hanya untuk 1 wsdl (yang memiliki 5 soapActions), IDE Eclipse saya digantung dan menghasilkan sekitar 100+ MB kelas / objek.
Manmohan_singh
-1

Saya menemukan cara alternatif yang jauh lebih sederhana untuk menghasilkan pesan sabun. Diberikan Objek Orang:

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
}

Di bawah ini adalah Penghasil Pesan Sabun sederhana:

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

Anda dapat menggunakan dengan:

 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
sumber