springboot-ws基础框架搭建步骤:
1.用idea创建spring-boot项目,具体的步骤省略;
2.pom添加webservice依赖:
org.springframework.boot
spring-boot-starter-web-services
wsdl4j
wsdl4j
3.添加配置类,这是springboot-ws的核心配置类:
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
@Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/ws/*");
}
@Bean(name = "sso")
public Wsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("SSOWebServiceSoap");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace("http://tempuri.org/");
wsdl11Definition.setSchema(countriesSchema);
wsdl11Definition.setCreateSoap11Binding(true);
wsdl11Definition.setCreateSoap12Binding(true);
Properties soapActions = new Properties();
soapActions.setProperty("ApplicationRegister", "http://tempuri.org/ApplicationRegister");
soapActions.setProperty("LoginVerify", "http://tempuri.org/LoginVerify");
wsdl11Definition.setSoapActions(soapActions);
return wsdl11Definition;
}
@Bean
public XsdSchema countriesSchema() {
return new SimpleXsdSchema(new ClassPathResource("sso.xsd"));
}
}
4. 在resource文件夹下创建xsd文件如下,其中ApplicationRegister和ApplicationRegisterResponse分别表示请求的对象以及响应的结果对象,可以在配置类中指定该文件的位置:
指定位置:
@Bean
public XsdSchema countriesSchema() {
return new SimpleXsdSchema(new ClassPathResource("sso.xsd"));
}
5. 在xsd文件上右键操作,根据xsd生成实体类:
6. 创建Endpoint类,Endpoint类主要用于描述webservice提供的方法:
@Endpoint
public class SsoEndpointApi {
private static final String NAMESPACE_URI = "http://tempuri.org/";
private SsoEndpointService ssoEndpointService;
/*
*方法说明:系统注册
* */
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "ApplicationRegister")
@ResponsePayload
public ApplicationRegisterResponse applicationRegister(@RequestPayload ApplicationRegister applicationRegister) {
return ssoEndpointService.applicationRegister(applicationRegister);
}
转换注意事项:
1. 将url地址的风格统一,spring-ws发布的webservice默认url是http://xx:xx/xxx.wsdl
,不符合常规的http://xx:xx/xxx?wsdl
格式,我们可以利用urlrewritefilter
去做一下转发:
添加依赖:
org.tuckey
urlrewritefilter
4.0.4
实现UrlRewriteFilter:
package com.winning.webService.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
import org.tuckey.web.filters.urlrewrite.Conf;
import org.tuckey.web.filters.urlrewrite.UrlRewriteFilter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import java.io.IOException;
/**
* @author zhanghong
* @since 2018-08-17 16:01
**/
@Component
public class WsdlUrlRewriteFilter extends UrlRewriteFilter {
private static final String CONFIG_LOCATION = "classpath:/urlrewrite.xml";
@Value(CONFIG_LOCATION)
private Resource resource;
@Override
protected void loadUrlRewriter(FilterConfig filterConfig) throws ServletException {
try {
Conf conf = new Conf(filterConfig.getServletContext(), resource.getInputStream(), resource.getFilename(), "");
checkConf(conf);
} catch (IOException ex) {
throw new ServletException("无法读取配置文件: " + CONFIG_LOCATION, ex);
}
}
}
配置转发规则
根据上面的CONFIG_LOCATION
指明的位置,新建配置文件urlrewrite.xml
,下面是一个例子
/ws/countries[\?]+wsdl
/ws/countries.wsdl
2. springboot-ws 生成wsdl时候,所有的请求默认带上后缀名Request, 所有的响应默认带上后缀名Response,如果不带上,则识别不了,但是如果之前的cxf框架请求后缀不带Request,那么改造的时候需要如下的配置:
自定义MyWsdl11Definition以及依赖的其他相关类:
public class MyWsdl11Definition implements Wsdl11Definition, InitializingBean {
private final InliningXsdSchemaTypesProvider typesProvider = new InliningXsdSchemaTypesProvider();
private final SuffixBasedMessagesProvider messagesProvider = new MySuffixBasedMessagesProvider();
private final SuffixBasedPortTypesProvider portTypesProvider = new MySuffixBasedPortTypesProvider();
private final SoapProvider soapProvider = new SoapProvider();
private final ProviderBasedWsdl4jDefinition delegate = new ProviderBasedWsdl4jDefinition();
private String serviceName;
public MyWsdl11Definition() {
delegate.setTypesProvider(typesProvider);
delegate.setMessagesProvider(messagesProvider);
delegate.setPortTypesProvider(portTypesProvider);
delegate.setBindingsProvider(soapProvider);
delegate.setServicesProvider(soapProvider);
}
public void setTargetNamespace(String targetNamespace) {
delegate.setTargetNamespace(targetNamespace);
}
public void setSchema(XsdSchema schema) {
typesProvider.setSchema(schema);
}
public void setSchemaCollection(XsdSchemaCollection schemaCollection) {
typesProvider.setSchemaCollection(schemaCollection);
}
public void setPortTypeName(String portTypeName) {
portTypesProvider.setPortTypeName(portTypeName);
}
public void setRequestSuffix(String requestSuffix) {
portTypesProvider.setRequestSuffix(requestSuffix);
messagesProvider.setRequestSuffix(requestSuffix);
}
public void setResponseSuffix(String responseSuffix) {
portTypesProvider.setResponseSuffix(responseSuffix);
messagesProvider.setResponseSuffix(responseSuffix);
}
public void setFaultSuffix(String faultSuffix) {
portTypesProvider.setFaultSuffix(faultSuffix);
messagesProvider.setFaultSuffix(faultSuffix);
}
public void setCreateSoap11Binding(boolean createSoap11Binding) {
soapProvider.setCreateSoap11Binding(createSoap11Binding);
}
public void setCreateSoap12Binding(boolean createSoap12Binding) {
soapProvider.setCreateSoap12Binding(createSoap12Binding);
}
public void setSoapActions(Properties soapActions) {
soapProvider.setSoapActions(soapActions);
}
public void setTransportUri(String transportUri) {
soapProvider.setTransportUri(transportUri);
}
public void setLocationUri(String locationUri) {
soapProvider.setLocationUri(locationUri);
}
public void setServiceName(String serviceName) {
soapProvider.setServiceName(serviceName);
this.serviceName = serviceName;
}
@Override
public void afterPropertiesSet() throws Exception {
if (!StringUtils.hasText(delegate.getTargetNamespace()) && typesProvider.getSchemaCollection() != null &&
typesProvider.getSchemaCollection().getXsdSchemas().length > 0) {
XsdSchema schema = typesProvider.getSchemaCollection().getXsdSchemas()[0];
setTargetNamespace(schema.getTargetNamespace());
}
if (!StringUtils.hasText(serviceName) && StringUtils.hasText(portTypesProvider.getPortTypeName())) {
soapProvider.setServiceName(portTypesProvider.getPortTypeName() + "Service");
}
delegate.afterPropertiesSet();
}
@Override
public Source getSource() {
return delegate.getSource();
}
}
public class MySuffixBasedMessagesProvider extends SuffixBasedMessagesProvider {
protected String requestSuffix = DEFAULT_REQUEST_SUFFIX;
public String getRequestSuffix() {
return this.requestSuffix;
}
public void setRequestSuffix(String requestSuffix) {
this.requestSuffix = requestSuffix;
}
@Override
protected boolean isMessageElement(Element element) {
if (isMessageElement0(element)) {
String elementName = getElementName(element);
Assert.hasText(elementName, "Element has no name");
return elementName.endsWith(getResponseSuffix())
|| (getRequestSuffix().isEmpty() ? true : elementName.endsWith(getRequestSuffix()))
|| elementName.endsWith(getFaultSuffix());
}
return false;
}
protected boolean isMessageElement0(Element element) {
return "element".equals(element.getLocalName())
&& "http://www.w3.org/2001/XMLSchema".equals(element.getNamespaceURI());
}
}
public class MySuffixBasedPortTypesProvider extends SuffixBasedPortTypesProvider {
private String requestSuffix = DEFAULT_REQUEST_SUFFIX;
public String getRequestSuffix() {
return requestSuffix;
}
public void setRequestSuffix(String requestSuffix) {
this.requestSuffix = requestSuffix;
}
@Override
protected String getOperationName(Message message) {
String messageName = getMessageName(message);
String result = null;
if (messageName != null) {
if (messageName.endsWith(getResponseSuffix())) {
result = messageName.substring(0, messageName.length() - getResponseSuffix().length());
} else if (messageName.endsWith(getFaultSuffix())) {
result = messageName.substring(0, messageName.length() - getFaultSuffix().length());
} else if (messageName.endsWith(getRequestSuffix())) {
result = messageName.substring(0, messageName.length() - getRequestSuffix().length());
}
}
return result;
}
@Override
protected boolean isInputMessage(Message message) {
String messageName = getMessageName(message);
return messageName != null && !messageName.endsWith(getResponseSuffix());
}
private String getMessageName(Message message) {
return message.getQName().getLocalPart();
}
}
在配置类WebServiceConfig中添加配置:
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
@Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/ws/*");
}
@Bean(name = "sso")
public Wsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
//DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
MyWsdl11Definition wsdl11Definition = new MyWsdl11Definition();
wsdl11Definition.setPortTypeName("SSOWebServiceSoap");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setRequestSuffix("");
wsdl11Definition.setTargetNamespace("http://tempuri.org/");
wsdl11Definition.setSchema(countriesSchema);
wsdl11Definition.setCreateSoap11Binding(true);
wsdl11Definition.setCreateSoap12Binding(true);
Properties soapActions = new Properties();
soapActions.setProperty("ApplicationRegister", "http://tempuri.org/ApplicationRegister");
soapActions.setProperty("LoginVerify", "http://tempuri.org/LoginVerify");
wsdl11Definition.setSoapActions(soapActions);
return wsdl11Definition;
}
@Bean
public XsdSchema countriesSchema() {
return new SimpleXsdSchema(new ClassPathResource("sso.xsd"));
}
@Override
public void addInterceptors(List interceptors) {
interceptors.add(new CustomEndpointInterceptor());
}
}
3. 将名称空间前缀更改SOAP-ENV
为soap:
添加
CustomEndpointInterceptor
public class CustomEndpointInterceptor extends EndpointInterceptorAdapter {
private static final String DEFAULT_NS = "xmlns:SOAP-ENV";
private static final String SOAP_ENV_NAMESPACE = "http://schemas.xmlsoap.org/soap/envelope/";
private static final String PREFERRED_PREFIX = "soap";
private static final String HEADER_LOCAL_NAME = "Header";
private static final String BODY_LOCAL_NAME = "Body";
private static final String FAULT_LOCAL_NAME = "Fault";
@Override
public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
SaajSoapMessage soapResponse = (SaajSoapMessage) messageContext.getResponse();
alterSoapEnvelope(soapResponse);
return super.handleResponse(messageContext, endpoint);
}
@Override
public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
SaajSoapMessage soapResponse = (SaajSoapMessage) messageContext.getResponse();
alterSoapEnvelope(soapResponse);
return super.handleFault(messageContext, endpoint);
}
private void alterSoapEnvelope(SaajSoapMessage soapResponse) {
try {
SOAPMessage soapMessage = soapResponse.getSaajMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
SOAPHeader header = soapMessage.getSOAPHeader();
SOAPBody body = soapMessage.getSOAPBody();
SOAPFault fault = body.getFault();
envelope.removeNamespaceDeclaration(envelope.getPrefix());
envelope.addNamespaceDeclaration(PREFERRED_PREFIX, SOAP_ENV_NAMESPACE);
envelope.setPrefix(PREFERRED_PREFIX);
header.setPrefix(PREFERRED_PREFIX);
body.setPrefix(PREFERRED_PREFIX);
if (fault != null) {
fault.setPrefix(PREFERRED_PREFIX);
}
Iterator it = body.getChildElements();
while (it.hasNext()) {
SOAPBodyElement node = it.next();
node.setPrefix("");
Iterator it2 = node.getChildElements();
while (it2.hasNext()) {
SOAPBodyElement node2 = it2.next();
node2.setPrefix("");
}
}
soapMessage.saveChanges();
} catch (SOAPException e) {
e.printStackTrace();
}
}
}
在WebServiceConfig中添加该拦截器:
@Override
public void addInterceptors(List interceptors) {
interceptors.add(new CustomEndpointInterceptor());
}