Spring ws small example

1. Introduction
  Spring Web Service is committed to developing contract-first SOAP web services, which can flexibly process XML content in many ways; contract-first means that when we start to write a Web Service, we first write WSDL, or dynamically generate XSD files after WSDL instead of writing java code first and then generating WSDL from the code. The main features are:
  1. Powerful Mapping function: You can map the received XML request to any Object based on message content, SOAP Action header or Xpath expression.
  2. Support a large number of XML APIs: not only can use JAXP APIS such as DOM, SAX, Stax, but also JDOM, dom4j, XOM, and even directly use marshalling technologies (which can directly convert xml content into java objects) to operate xml.
  3. Flexible XML marshalling: Spring Web Services is built on the oxm module of the spring framework and supports JAXB1 and JAXB2, Castor, XMLBeans, JiBX and XStream.
  4. Support message security mechanism: The security mechanism of Spring WS allows you to sign SOAP messages, encrypt and decrypt, and additionally authenticate.

2. Example description
  This example refers to the example explained in Spring-ws-refenrenc, implements a holiday reservation function, and makes some extensions on this basis, using JAXB2 to directly convert the request object into a message to send, and return the name and name after the reservation is successful. Schedule a number and directly convert the returned result into an Object.

3. The example starts, first edit the XSD
  Spring-WS does not recommend writing wsdl files directly. We can write relatively simple XSD files and then generate corresponding wsdl files.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
	xmlns:hr="http://fengyilin.com/hr/schemas" elementFormDefault="qualified"
	targetNamespace="http://fengyilin.com/hr/schemas">
	<xs:element name="HolidayRequest">
		<xs:complexType>
			<xs:all>                           (4)
				<xs:element name="Holiday" type="hr:HolidayType" />     (1)
				<xs:element name="Employee" type="hr:EmployeeType" />         			</xs:all>
		</xs:complexType>
	</xs:element>
	<xs:element name="HolidayResponse">
		<xs:complexType>
			<xs:sequence>           (5)
				<xs:element name="name" type="xs:string" />
				<xs:element name="number" type="xs:integer" /> (3)
			</xs:sequence>
		</xs:complexType>
	</xs:element>
	<xs:complexType name="HolidayType">
		<xs:sequence>
			<xs:element name="StartDate" type="xs:date" />    (2)
			<xs:element name="EndDate" type="xs:date" />      (2)
		</xs:sequence>
	</xs:complexType>
	<xs:complexType name="EmployeeType">
		<xs:sequence>
			<xs:element name="FirstName" type="xs:string" />   (3)
			<xs:element name="LastName" type="xs:string" />
		</xs:sequence>
	</xs:complexType>
</xs:schema>

(1) Refer to the data type under our own defined namespace
(2) Use xsd:date data type, including year, month, day
(3) xsd:string, xsd:integer define the corresponding attributes
(4) xsd:all Indicates that the order of attributes <Holiday/> and <Employee/> is arbitrary
(5) xsd:sequence indicates that the order of attributes should be consistent
4. Generate wsdl
1. Create a dynamic web project SpringWebService
2. Edit web.xml
 
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	id="WebApp_ID" version="3.1">
	<display-name>SpringWebService</display-name>

	<servlet>
		<servlet-name>spring-ws</servlet-name>
		<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
		</init-param>
		<init-param>
			<param-name>transformWsdlLocations</param-name>
			<param-value>true</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
		<async-supported>true</async-supported>
	</servlet>
	<servlet-mapping>
		<servlet-name>spring-ws</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	<context-param>
		<param-name>log4jConfigLocation</param-name>
		<param-value>/resources/log4j/log4j.properties</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
	</listener>
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
	</welcome-file-list>
</web-app>



Compared with the SpringMvc project, here just replace the DispatcherServlet with MessageDispatcherServlet. Set the transformWsdlLoactions property to true to start the location conversion function, thereby dynamically converting relative paths to absolute paths.
3. Edit the context configuration file
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:sws="http://www.springframework.org/schema/web-services"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-2.0.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
	
	<context:component-scan base-package="test.spring.ws.service" /> (1)
	<sws:annotation-driven />                                    (2)
	<sws:dynamic-wsdl id="holiday"                          (3)
		portTypeName="HumanResource"             (4)
		locationUri="/holidayService/"                    (5)
		targetNamespace="http://fengyilin.com/hr/definitions">   (6)
		<sws:xsd location="/resources/xsd/hr.xsd" />        (7)
	</sws:dynamic-wsdl>
</beans>

(1) Specify the class scan path
(2) Indicate the use of annotation-driven
(3) The id attribute indicates the URL that WSDL can be obtained, where id is holiday, indicating that the WSDL file in the servlet context is holiday.wsdl. Complete access path Yes: http://host:port/project name/(locationUri)/holiday.wsdl, corresponding to this example is http://localhost:8080/SpringWebService/holidayService/holiday.wsdl; dynamic-wsdl is marked during program execution Dynamically generate wsdl
(4) Specify that the port type of WSDL is HumanResource
(5) Specify a relative path, because the value of transformWsdlLocations is set to true in web.xml, so the relative path can be used here to indicate the access path of the wsdl service.
(6) WDSL's own namespace is specified. If not set, wsdl uses the same namespace as the XSD schema
(7) The location of the xsd file used to generate wsdl is specified
4. After the application starts, access the corresponding url to generate wsdl file, the content is as follows
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
	xmlns:sch="http://fengyilin.com/hr/schemas" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
	xmlns:tns="http://fengyilin.com/hr/definitions" targetNamespace="http://fengyilin.com/hr/definitions">
	<wsdl:types>
		<xs:schema xmlns:hr="http://fengyilin.com/hr/schemas"
			xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
			targetNamespace="http://fengyilin.com/hr/schemas">
			<xs:element name="HolidayRequest">
				<xs:complexType>
					<xs:all>
						<xs:element name="Holiday" type="hr:HolidayType" />
						<xs:element name="Employee" type="hr:EmployeeType" />
					</xs:all>
				</xs:complexType>
			</xs:element>
			<xs:element name="HolidayResponse">
				<xs:complexType>
					<xs:sequence>
						<xs:element name="name" type="xs:string" />
						<xs:element name="number" type="xs:integer" />
					</xs:sequence>
				</xs:complexType>
			</xs:element>
			<xs:complexType name="HolidayType">
				<xs:sequence>
					<xs:element name="StartDate" type="xs:date" />
					<xs:element name="EndDate" type="xs:date" />
				</xs:sequence>
			</xs:complexType>
			<xs:complexType name="EmployeeType">
				<xs:sequence>
					<xs:element name="FirstName" type="xs:string" />
					<xs:element name="LastName" type="xs:string" />
				</xs:sequence>
			</xs:complexType>
		</xs:schema>
	</wsdl:types>
	<wsdl:message name="HolidayRequest">
		<wsdl:part element="sch:HolidayRequest" name="HolidayRequest"></wsdl:part>
	</wsdl:message>
	<wsdl:message name="HolidayResponse">
		<wsdl:part element="sch:HolidayResponse" name="HolidayResponse"></wsdl:part>
	</wsdl:message>
	<wsdl:portType name="HumanResource">
		<wsdl:operation name="Holiday">
			<wsdl:input message="tns:HolidayRequest" name="HolidayRequest"></wsdl:input>
			<wsdl:output message="tns:HolidayResponse" name="HolidayResponse"></wsdl:output>
		</wsdl:operation>
	</wsdl:portType>
	<wsdl:binding name="HumanResourceSoap11" type="tns:HumanResource">
		<soap:binding style="document"
			transport="http://schemas.xmlsoap.org/soap/http" />
		<wsdl:operation name="Holiday">
			<soap:operation soapAction="" />
			<wsdl:input name="HolidayRequest">
				<soap:body use="literal" />
			</wsdl:input>
			<wsdl:output name="HolidayResponse">
				<soap:body use="literal" />
			</wsdl:output>
		</wsdl:operation>
	</wsdl:binding>
	<wsdl:service name="HumanResourceService">
		<wsdl:port binding="tns:HumanResourceSoap11" name="HumanResourceSoap11">
			<soap:address location="http://localhost:8080/SpringWebService/holidayService" />
		</wsdl:port>
	</wsdl:service>
</wsdl:definitions>


*Although it is very convenient to generate WSDL directly from XSDs at runtime, there are several problems in this way:
(1) With the upgrade of Spring-ws version, the WSDL generated from the same XSD may change.
(2) Even if it is only generated once, and then the wsdl is cached, the request will be slow due to the generation process.
So the recommended practice is: in the development stage, use <dynamic-wsdl> to dynamically generate, when publishing the application, use the browser to download the wsdl, and then use <static-wsdl>, so that the WSDL can be guaranteed to remain unchanged

. Change the part about sws in servlet-context.xml above to the following
<sws:static-wsdl id="holiday" location="/resources/wsdl/holiday.wsdl"/>


5. Implementing Endpoint
Because it adopts the assembly technology of JAXB2, there is no xml operation, and the implementation of Endpoint is quite simple
package test.spring.ws.service.endpoint;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;

import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.Namespace;
import org.jdom2.filter.Filters;
import org.jdom2.xpath.XPathExpression;
import org.jdom2.xpath.XPathFactory;
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.xml.xpath.Jaxp13XPathTemplate;
import org.springframework.xml.xpath.XPathOperations;

import test.spring.ws.entity.HolidayRequest;
import test.spring.ws.entity.HolidayResponse;
import test.spring.ws.service.HumanResourceService;

@Endpoint
public class HolidayEndpoint {
	private static final String NAMESPACE_URI = "http://fengyilin.com/hr/schemas";

	private HumanResourceService humanResourceService;

	@Autowired
	public HolidayEndpoint(HumanResourceService humanResourceService) throws JDOMException {
		this.humanResourceService = humanResourceService;
	}

	@PayloadRoot(namespace = NAMESPACE_URI, localPart = "HolidayRequest") (1)
	@ResponsePayload     (2)
	public HolidayResponse handleHolidayRequest(@RequestPayload HolidayRequest request) throws Exception {   (3)

		humanResourceService.bookHoliday(request.getHoliday().getStartDate(), request.getHoliday().getEndDate(),
				request.getEmployee().getFirstName());

		HolidayResponse response = new HolidayResponse();
		response.setName(request.getEmployee().getFirstName()+"_"+request.getEmployee().getLastName());
		response.setNumber((int) (100*Math.random()));
		return response;
	}
}


(1) Because the SOAP protocol has nothing to do with transport, Spring-ws does not support Mapping the message to the Endpoint through the URL of the HTTP request, but through the content of the message, including the namespace of the message and the local name of the message, so the PayloadRoot annotation in the The properties must be correct and consistent with when the client calls them.
(2) The ResponsePayload annotation indicates that there is content to be returned to the client
(3) HolidayResponse and HolidayRequest are classes annotated with JAXB annotations and can be directly generated using xsd files. (Here, in order to understand the direct conversion of xsd to java class, I wrote these two classes manually, and the classes they depend on), how to automatically generate, you can refer to http://fengyilin.iteye.com/admin/blogs/2344183

The above is the main code of the server, let's take a brief look at the client call
/*
 * Copyright 2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package test.spring.ws.client;

import java.io.IOException;
import java.util.Date;

import javax.xml.transform.Source;

import org.springframework.core.io.ClassPathResource;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.util.ClassUtils;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.xml.transform.ResourceSource;
import org.springframework.xml.transform.StringResult;

import test.spring.ws.entity.EmployeeType;
import test.spring.ws.entity.HolidayRequest;
import test.spring.ws.entity.HolidayResponse;
import test.spring.ws.entity.HolidayType;
import test.spring.ws.jaxb2.JaxbUtil;

public class HolidayClient {

	private final WebServiceTemplate webServiceTemplate = new WebServiceTemplate();

	// send to the configured default URI
	public void sendAndReceive() throws Exception {
		Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
		marshaller.setPackagesToScan(new String[] { ClassUtils.getPackageName(HolidayRequest.class) });
		marshaller.afterPropertiesSet();
		WebServiceTemplate msbServiceTemplate = new WebServiceTemplate(marshaller);  -- (1)
		HolidayRequest request = new HolidayRequest();
		EmployeeType employee = new EmployeeType();
		employee.setFirstName("cc");
		employee.setLastName("dd");
		request.setEmployee(employee);

		HolidayType holiday = new HolidayType();
		holiday.setEndDate(new Date());
		holiday.setStartDate(new Date());

		request.setHoliday(holiday);
		msbServiceTemplate.setDefaultUri("http://localhost:8080/SpringWebService/services");
		HolidayResponse response = (HolidayResponse) msbServiceTemplate.marshalSendAndReceive(request);--(2)
		
		
		System.out.println("-------");
		System.out.println(response);
		System.out.println("-------");
	}

	public static void main(String[] args) throws Exception {
		HolidayClient client = new HolidayClient();
		client.sendAndReceive();
	}
}


(1) Using marshalling technology, directly convert Java Object into message content and send
(2) Assemble the returned result directly into Java object The

complete project directory is as follows:



Please refer to the attachment for the specific code of the project

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326853778&siteId=291194637