1.1.34.11. fejezet, SOAP szolgáltatás
Kapcsolódó hivatokzások
- Spring Boot SOAP Webservice Example (Github repo)
- Creating a SOAP Web Service
- Java XML and JSON Binding
- Consuming a SOAP web service (Spring SOAP Client)
- ForrasUploadSOAPServer (Github repo)
- Spring WS Get Soap Header in Server
- Securing SOAP Web Services With Keycloak
Alkalmazás konfiguráció
Ha a componensek (pl.: @Configuration) különböző könyvtárakban vannak, használjuk a @ComponentScan annotációt (dokumentáció).
package hu.infokristaly.forrasuploadsoapserver; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; @SpringBootApplication @ComponentScan(basePackages = {"hu.infokristaly"}) public class ForrasUploadSoapServerApplication { public static void main(String[] args) { SpringApplication.run(ForrasUploadSoapServerApplication.class, args); } }
WSDL generálása Schema XSD-ből
A következő formában szerkesszük meg a séma definíciót, és helyezzük a resources könyvtárba (src/main/resources/fileuplaod.xsd):
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://infokristaly.hu/fileupload" targetNamespace="http://infokristaly.hu/fileupload" elementFormDefault="qualified"> <xs:element name="uploadRequest"> <xs:complexType> <xs:sequence> <xs:element name="fileName" type="xs:string"/> <xs:element name="content" type="xs:base64Binary" xmime:expectedContentTypes="application/octet-stream"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="uploadResponse"> <xs:complexType> <xs:sequence> <xs:element name="return" type="xs:int"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
Az operátorok a Request / Response előtagjai lesznek (upload).
Alkalmazzuk a jaxb2-maven-plugin maven bővítményt a pom.xml-ben a következőként:
<plugins> ... <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxb2-maven-plugin</artifactId> <version>3.1.0</version> <executions> <execution> <id>xjc</id> <goals> <goal>xjc</goal> </goals> </execution> </executions> <configuration> <sources> <source>src/main/resources/fileupload.xsd</source> <!-- Saját xsd állományunk helye --> </sources> <outputDirectory>src/main/java</outputDirectory> <!-- generált kód helye --> <clearOutputDir>false</clearOutputDir> </configuration> </plugin> ... </plugins>
Majd a compile parancsal generáljuk le a Java osztályokat:
mvn compile
Újra generálás előtt töröljük a projekt target könyvtárát!
WebService konfiguráció
package hu.infokristaly.soap; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.ws.config.annotation.EnableWs; import org.springframework.ws.config.annotation.WsConfigurerAdapter; import org.springframework.ws.transport.http.MessageDispatcherServlet; import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition; import org.springframework.xml.xsd.SimpleXsdSchema; import org.springframework.xml.xsd.XsdSchema; @Configuration @EnableWs public class SOAPWebServiceConfig extends WsConfigurerAdapter { @Bean public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) { MessageDispatcherServlet servlet = new MessageDispatcherServlet(); servlet.setApplicationContext(applicationContext); servlet.setTransformWsdlLocations(true); return new ServletRegistrationBean(servlet, "/ws/*"); // a servlet a http://localhost:8080/ws/* alatti kéréseket szolgálja ki } @Bean(name = "FileUploadServiceWsdl") public DefaultWsdl11Definition calculatorServiceDefinition(XsdSchema calculatorServiceSchema) { DefaultWsdl11Definition wsdlDefinition = new DefaultWsdl11Definition(); wsdlDefinition.setPortTypeName("FileUploadServicePort"); wsdlDefinition.setLocationUri("/ws/fileuplaod-service"); // a kérések a http://localhost:8080/ws/fileuplaod-service soap:address-re érkeznek majd wsdlDefinition.setTargetNamespace("http://infokristaly.hu/fileuplaod"); wsdlDefinition.setSchema(fileUplaodServiceSchema()); return wsdlDefinition; } @Bean public XsdSchema fileUplaodServiceSchema() { return new SimpleXsdSchema(new ClassPathResource("fileupload.xsd")); } }
Ügyeljünk arra, hogy a wsdlDefinition.setTargetNamespace() metódusnak a xs:schema targetNamespace értékével megegyező paraméterű legyen. Ez a wsdl generálásánál játszik szerepet.
WebService végpont
package hu.infokristaly.soap; import hu.infokristaly.fileservice.FileUploadService; import hu.infokristaly.fileupload.UploadRequest; import hu.infokristaly.fileupload.UploadResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ws.server.endpoint.annotation.Endpoint; import org.springframework.ws.server.endpoint.annotation.PayloadRoot; import org.springframework.ws.server.endpoint.annotation.RequestPayload; import org.springframework.ws.server.endpoint.annotation.ResponsePayload; import org.springframework.ws.soap.SoapHeaderElement; import org.springframework.ws.soap.server.endpoint.annotation.SoapHeader; import jakarta.xml.bind.JAXBContext; import jakarta.xml.bind.JAXBException; import jakarta.xml.bind.Unmarshaller; @Endpoint public class FileUploadEndpoint { private FileUploadService fileUploadService; @Autowired public FileUploadEndpoint(FileUploadService fileUploadService) { this.fileUploadService = fileUploadService; } @PayloadRoot(namespace = "http://infokristaly.hu/fileupload", localPart = "uploadRequest") @ResponsePayload public UploadResponse fileUpload(@RequestPayload UploadRequest request, @SoapHeader("{" + Authentication.AUTH_NS + "}authentication") SoapHeaderElement auth) { Authentication authentication = getAuthentication(auth); if (authentication == null || !authentication.getUsername().equals("username") || !authentication.getPassword().equals("password")) { System.out.println("Invalid authentication"); } UploadResponse response = new UploadResponse(); response.setReturn(fileUploadService.fileUpload(request)); return response; } private Authentication getAuthentication(SoapHeaderElement header){ Authentication authentication = null; try { JAXBContext context = JAXBContext.newInstance(Authentication.class); Unmarshaller unmarshaller = context.createUnmarshaller(); authentication = (Authentication) unmarshaller.unmarshal(header.getSource()); } catch (JAXBException e) { e.printStackTrace(); } return authentication; } }
Ügyeljünk arra, hogy az xsd fájlban a namespace és a targetNamespace / xmlns:tns megegyező legyen a @PayloadRoot namespace értékével, és a localPart értéke kis betűvel kezdődjön, mint ahogy az xsd-ben van definiálva.
Végül a szolgáltatás leíróját ellenőrizzük a http://localhost:8080/ws/FileUploadServiceWsdl.wsdl címen. A szolgáltatás leíró címét a SOAPWebServiceConfig-ban definiáltuk (FileUploadServiceWsdl).
Authenticatoin.java
A felhasználó azonosításra használt osztály a következő:
package hu.infokristaly.soap; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlElement; import jakarta.xml.bind.annotation.XmlRootElement; @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement(namespace = Authentication.AUTH_NS) public class Authentication { public static final String AUTH_NS = "https://infokristaly.hu/security"; @XmlElement(namespace = AUTH_NS) private String username; @XmlElement(namespace = AUTH_NS) private String password; public Authentication() { } public Authentication(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
FileUploadServiceImpl.java
A szolgáltatás implementációja pedig a következő:
package hu.infokristaly.fileservice; import hu.infokristaly.fileupload.UploadRequest; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Paths; @Service public class FileUploadServiceImpl implements FileUploadService { @Value("${upload.dir}") private String uploadDir; public int fileUpload(UploadRequest uploadRequest) { try { uploadRequest.getContent().writeTo(new FileOutputStream(Paths.get(uploadDir, uploadRequest.getFileName()).toFile())); } catch (IOException e) { throw new RuntimeException(e); } return uploadRequest.getFileName().length(); } }
Tesztelés SoapUI-al
WSDL-ből generálhatunk SOAP XML-t a SoapUI-ba. Az xml tartalomra minta az alábbi:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:fil="http://infokristaly.hu/fileupload"> <soapenv:Header> <auth:authentication xmlns:auth="https://infokristaly.hu/security"> <auth:username>username</auth:username> <auth:password>password</auth:password> </auth:authentication> </soapenv:Header> <soapenv:Body> <fil:uploadRequest> <fil:fileName>README.md</fil:fileName> <fil:content>dGVzdA==</fil:content> </fil:uploadRequest> </soapenv:Body> </soapenv:Envelope>
Tesztelés Postman-al
Készítsünk egy POST hívást, másoljuk be a WebService URL-jét (pl.: http://localhost:8080/ws/fileuplaod-service). Állítsuk be a Headers-be a "Content-Type"-ot "text/xml"-re. A Body-ba másoljuk be "raw" tartalomba a SOAP xml-t és állítsuk be a formátumot "XML"-re.
Lásd még a Make HTTP calls using the SOAP protocol dokumentációban.
- A hozzászóláshoz be kell jelentkezni