场景
spring-ws
spring-ws官网:
https://spring.io/projects/spring-ws
SpringWebServices(Spring-WS)是Spring社区的一个产品,专注于创建文档驱动的Web服务。SpringWebServices旨在促进契约优先的SOAP服务开发,允许使用多种操作XML有效负载的方式之一创建灵活的Web服务。该产品基于Spring本身,这意味着您可以使用Spring概念,例如依赖注入作为Web服务的一个组成部分。
Soap
SOAP(Simple Object AccessProtocol)简单对象访问协议。它是轻型协议,用于分散的、分布式计算环境中交换信息。SOAP有助于以独立于平台的方式访问对象、服务和服务器。它借助于XML,提供了HTTP所需的扩展。
Soap与Http区别
都是底层的通信协议,请求包的格式不同,soap包是XML格式,http纯文本格式
soap 的 可以传递结构化的 数据,http只能传输纯文本数据;
WSDL
WSDL(Web服务描述语言,Web Services Description Language)是为描述Web服务发布的XML格式。
XSD
XML Schema Definition缩写。
XML Schema 是基于 XML 的 DTD 替代者。
XML Schema 可描述 XML 文档的结构。
XML Schema 语言也可作为 XSD(XML Schema Definition)来引用。
XSD教程:菜鸟教程
http://www.runoob.com/schema/schema-intro.html
实现
添加依赖
除了springboot的基本依赖,还要添加spring-ws以及wsdl4j的依赖。
打开项目的pom.xml
这里为了设置打包时去掉tomcat的jar包。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
</dependency>
添加插件
为了能实现根据xsd文件自动生成代码,还要添加maven的jaxb2插件。
打开pom.xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaDirectory>
${project.basedir}/src/main/resources/xsd/
</schemaDirectory>
<outputDirectory>
${project.basedir}/src/main/java
</outputDirectory>
<clearOutputDir>
false
</clearOutputDir>
<encoding>utf-8</encoding>
</configuration>
</plugin>
</plugins>
<finalName></finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
将下面这部分代码放在如上的位置:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaDirectory>
${project.basedir}/src/main/resources/xsd/
</schemaDirectory>
<outputDirectory>
${project.basedir}/src/main/java
</outputDirectory>
<clearOutputDir>
false
</clearOutputDir>
<encoding>utf-8</encoding>
</configuration>
</plugin>
注:
1.${project.basedir} 是内置属性,表示项目根目录,即包含pom.xml文件的目录。
2.可以通过<schemaDirectory>标签指明xsd文件的位置。比如这里就是
3.可以通过 <outputDirectory>来指定jaxb2根据xsd文件生成实体类的位置
这里就是src/main/java下,然后jaxb2插件生成代码是以命名空间来确定包名。
比如命名空间是http://test.com/webservice/pda
那么就会在src/main/java下生成com/test/wewwbservice/pda目录,并在此目录下生成对应代码。
4.可以通过<clearOutputDir>设置重新生成代码时时候清除输出目录,默认是true,这里设置为false,要注意如果后期需要修改xsd文件并且可能会导致有重名的实体类时,修改为true。
编写schema文件/xsd文件
spring-ws的发布,都是以一个schema文件(xsd)定义开始的,它描述了web service的参数以及返回的数据。
在上面插件里指明的xsd所在目录下,新建xsd文件,后缀名是.xsd
xsd文件示例代码:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://test.com/webservice/pda"
targetNamespace="http://test.com/webservice/pda" elementFormDefault="qualified">
<!--登录方法-->
<xs:element name="PdaLoginRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="username" type="xs:string"/>
<xs:element name="password" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<!--登录响应-->
<xs:element name="PdaLoginResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="request-result" type="tns:LoginRequestResult"/>
<xs:element name="menu-result" type="tns:MenuList"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="MenuList">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="menu" nillable="true" type="tns:Menu"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Menu">
<xs:sequence>
<xs:element name="menu" type="xs:string"/>
<xs:element name="url" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<!--登录响应结果-->
<xs:complexType name="LoginRequestResult">
<xs:sequence>
<xs:element name="request_result" type="xs:boolean"/>
<xs:element name="result_desc" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
注意将:xmlns:tns="http://test.com/webservice/pda"和targetNamespace="http://test.com/webservice/pda"改为自己的命名空间。
这里是实现一个简单的登录请求与相应。登录请求时传递两个参数username和password。
<xs:element name="username" type="xs:string"/>表示是string类型的username。
string是自带类型,如果要使用自定义类型,要使用登录响应中的类似这样:
<xs:element name="request-result" type="tns:LoginRequestResult"/>
然后登录后的响应是有两个自定义属性。
第一个request-result表示请求结果。请求结果里面有是否请求成功的布尔值属性和请求结果。
<!--登录响应结果-->
<xs:complexType name="LoginRequestResult">
<xs:sequence>
<xs:element name="request_result" type="xs:boolean"/>
<xs:element name="result_desc" type="xs:string"/>
</xs:sequence>
</xs:complexType>
第二个是登录成功后不同用户根据不同的权限返回不同的菜单List。
<xs:complexType name="MenuList">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="menu" nillable="true" type="tns:Menu"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Menu">
<xs:sequence>
<xs:element name="menu" type="xs:string"/>
<xs:element name="url" type="xs:string"/>
</xs:sequence>
</xs:complexType>
而每一个MenuList的属性又是一个自定义Menu,而每一个自定义Menu有两个属性。
一个是菜单的名字,一个是点击菜单后返回的url。
使用插件生成代码
jaxb2插件可以根据描述的xsd文件来帮我们生成相应的ws代码
使用Maven的install命令或者package就可以在设置的输出的目录下生成对应的实体类代码。
这里以IDEA为例,打开Maven命令面板。
双击运行install或者package会生成代码。
来到配置输出的目录下
编写Endpoint
SpringBoot的Endpoint主要是用来监控应用服务的运行状况,并集成在Mvc中提供查看接口。简单点说相当于一个url服务,就是将请求时的url与后台响应的方法对应起来。
其编写方法类似于Controller。
新建webservice包,包下新建EndPoint
package com.ws.api.webservice;
import com.ws.api.sys.service.LoginService;
import com.ws.api.sys.service.ProduceReceiveService;
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 javax.annotation.Resource;
import java.util.List;
/**
* PDA接口切点
* @author
* @version badao
* @see
* @since
**/
@Endpoint
public class PdaEndpoint {
@Resource
private LoginService loginService;//引入用户mapper
private static final String NAMESPACE_URI = "http://test.com/webservice/pda";
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "PdaLoginRequest")
@ResponsePayload
public PdaLoginResponse statusFeedbacke(@RequestPayload PdaLoginRequest request){
String username = request.getUsername();
String password = request.getPassword();
return loginService.loginRequest(username,password);
}
}
注:
其中@Endpoint作用类似于@Controller
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "PdaLoginRequest")声明命名空间,要与xsd文件中的一致。
@ResponsePayload 必加,方法的返回类型要与xsd定义的请求类型一致,方法参数里请求类型要与xsd文件中的一致。
我们可以通过request对象的get方法获取相应的请求参数。
然后将service方法中的返回类型设置为相应的响应类型。
LoginService 代码:
package com.ws.api.sys.service;
import com.test.webservice.pda.PdaLoginResponse;
import org.springframework.stereotype.Service;
@Service
public interface LoginService {
PdaLoginResponse loginRequest(String username, String password);
}
serviceImpl代码:
package com.ws.api.sys.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wongoing.webservice.pda.LoginRequestResult;
import com.wongoing.webservice.pda.Menu;
import com.test.webservice.pda.MenuList;
import com.test.webservice.pda.PdaLoginResponse;
import com.ws.api.sys.entity.SysUser;
import com.ws.api.sys.mapper.SysUserMapper;
import com.ws.api.sys.service.LoginService;
import com.ws.api.sys.shiro.ShiroHelper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class LoginServiceImpl implements LoginService {
@Resource
private SysUserMapper sysUserMapper;//引入用户mapper
@Override
public PdaLoginResponse loginRequest(String username, String password) {
PdaLoginResponse response = new PdaLoginResponse();
LoginRequestResult result = new LoginRequestResult();
MenuList menuList = new MenuList();
List<Menu> menus = menuList.getMenu();
//MD5加密开始
//String salt = SequenceUtil.getInst().getRandomCode(6);
//开始查询数据库中有没有用户名
QueryWrapper<SysUser> sysUserQueryWrapper = new QueryWrapper<SysUser>();
sysUserQueryWrapper.eq("account", username);
sysUserQueryWrapper.eq("is_delete", "0");
SysUser sysUser = sysUserMapper.selectOne(sysUserQueryWrapper);
String encryptPassword="";
if (sysUser == null) {
result.setRequestResult(false);
result.setResultDesc("用户名不存在");
} else {
if(sysUser.getSalt()!=null){
String salt =sysUser.getSalt();
//加密后的密碼
encryptPassword = ShiroHelper.SHA1(password, username + salt);
//用户名存在时判断密码是否正确
sysUserQueryWrapper.eq("password", encryptPassword);
SysUser sysUser2 = sysUserMapper.selectOne(sysUserQueryWrapper);
if (sysUser2 == null) {
result.setRequestResult(false);
result.setResultDesc("密码不正确");
} else {
Menu menu = new Menu();
menu.setMenu("生产领料收货");
menu.setUrl("/ProduceReceiveRequest");
menus.add(menu);
Menu m = new Menu();
m.setMenu("质检领料收货");
m.setUrl("/QualityReceiveRequest");
menus.add(m);
Menu m2 = new Menu();
m2.setMenu("单件补码");
m2.setUrl("/SolidCodeRequest");
menus.add(m);
result.setRequestResult(true);
result.setResultDesc("登录成功");
}
}
}
response.setRequestResult(result);
response.setMenuResult(menuList);
return response;
}
}
其他业务流程要结合具体业务编写,注意响应的返回格式。
编写配置类
在项目目录下新建config目录,并新建config类
package com.ws.api.config;
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;
@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 = "pda2wms")
public DefaultWsdl11Definition pdaWsdl11Definition(XsdSchema pda2wmsSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("WmsPort");
wsdl11Definition.setLocationUri("/");
wsdl11Definition.setTargetNamespace("http://test.com/webservice/pda");
wsdl11Definition.setSchema(pda2wmsSchema);
return wsdl11Definition;
}
@Bean
public XsdSchema pda2wmsSchema() {
return new SimpleXsdSchema(new ClassPathResource("/xsd/pda2wms.xsd"));
}
}
注:
wsdl11Definition.setPortTypeName("WmsPort");
接口说明:
设置用于此定义的端口类型名称。需要。
public void setPortTypeName(String portTypeName)
这里的WmsPort是自动生成的代码,跟实体类一起生成的。
其他参数详细说明参照:
类DefaultWsdl 11定义中英文对比API文档
https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/89394809
启动项目
编写项目启动类并启动:
package com.ws.api;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.retry.annotation.EnableRetry;
@SpringBootApplication
@EnableRetry
public class ApiApplication {
public static void main(String[] args) {
SpringApplication.run(ApiApplication.class, args);
}
}
启动项目后访问:
http://127.0.0.1:7878/ws/pda2wms.wsdl
本地是127.0.0.1,项目端口号是7878
发现web service已经成功发布了。
右键点击另存为
然后就可以使用SoapUI进行测试。测试方法见:
https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/89356462