spring boot 1.5.4 整合webService(十五)

简介:

Spring Boot整合web service

经验引用

之前用webserviceCXF框架,

 

很方便与简洁,但是悲催的是在部署到生产环境的WebSphere(was平台)下后,不能正常运行.

 

网上一查,原来WebSphereCXF的冲突问题由来已久,解决方案也五花八门,会有不必要的麻烦.既然如此趁项目的web service还在刚整合阶段,换个组件吧.

 

问了其它项目组同事以前是怎么实现的,说就是因为冲突问题以前都是采用了httpClient之类的组装xml发送原生http请求调用的.

 

处理方式欠妥,作者当然不能接受。既然spring能在WebSphere下正常运行,那么spring的组件能够成功运行的可能性相对较大。

 

研究考虑之后,决定选用spring-ws来实现webservice。事实证明选择是正确的。

spring-boot相关项目源码,

码云地址:https://git.oschina.net/wyait/springboot1.5.4.git

github地址https://github.com/wyait/spring-boot-1.5.4.git

 

spring-ws的资料相对较少,不像cxf那样一找就是一大堆,不过好在有官方示例和文档。

 

官方示例中使用了spring boot,这跟我当前的环境不谋而合,不过它示例了多个构建工具和Groovy等,看起来比较复杂难懂一些,这里我们就以单纯的maven来实现。

 

1      web Service服务端

新建项目:ws-server(源码地址:

码云地址:https://git.oschina.net/wyait/springboot1.5.4.git

github地址https://github.com/wyait/spring-boot-1.5.4.git


 

spring boot的工程,除了spring boot外还需要添加spring-wswsdl4j的依赖,当然后面生成代码还需要添加mavenjaxb2插件

1.1    pom导入依赖

 

<dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-ws</artifactId>

        <version>1.4.5.RELEASE</version>

      </dependency>

      <dependency>

        <groupId>wsdl4j</groupId>

        <artifactId>wsdl4j</artifactId>

      </dependency>

 

1.2    编写schema文件

spring-ws的发布,都是以一个schema文件(xsd)定义开始的,它描述了webservice 的参数以及返回的数据。

 

这是官方示例给出的countries.xsd,这里以它为例,更改下命名空间,因为jaxb2插件自动生成代码是以命名空间来确定包名的。手动生成不影响!

<xs:schemaxmlns:xs="http://www.w3.org/2001/XMLSchema"xmlns:tns="http://www.wyait.com/ws"

           targetNamespace="http://www.wyait.com/ws"elementFormDefault="qualified">

        <xs:elementname="getCountryRequest">

            <xs:complexType>

                <xs:sequence>

                    <xs:elementname="name" type="xs:string"/>

                </xs:sequence>

            </xs:complexType>

        </xs:element>

        <xs:elementname="getCountryResponse">

            <xs:complexType>

                <xs:sequence>

                    <xs:elementname="country" type="tns:country"/>

                </xs:sequence>

            </xs:complexType>

        </xs:element>

        <xs:complexTypename="country">

            <xs:sequence>

                <xs:elementname="name" type="xs:string"/>

                <xs:elementname="population" type="xs:int"/>

                <xs:elementname="capital" type="xs:string"/>

                <xs:elementname="currency" type="tns:currency"/>

            </xs:sequence>

        </xs:complexType>

        <xs:simpleTypename="currency">

            <xs:restrictionbase="xs:string">

                <xs:enumerationvalue="GBP"/>

                <xs:enumerationvalue="EUR"/>

                <xs:enumerationvalue="PLN"/>

            </xs:restriction>

        </xs:simpleType>

    </xs:schema>

1.3    jaxb2插件配置

pom文件配置jaxb2插件:

<plugin>

           <groupId>org.codehaus.mojo</groupId>

           <artifactId>jaxb2-maven-plugin</artifactId>

           <version>2.2</version>

           <configuration>

           <schemaDirectory>${project.basedir}/src/main/resources/schema</schemaDirectory>

              <outputDirectory>${project.basedir}/src/main/java</outputDirectory>

              <clearOutputDir>false</clearOutputDir>

           </configuration>

        </plugin>

eclipse开发工具:选中countries.xsd文件,右键:

wKioL1nPWDny8h3XAAB7xmx6idc226.png

IDEA开发工具:

coruntries.xsd右键,然后选中web service那一项,generatejava code from xml schema using jaxb

wKiom1nPWIaj2sJeAAFSKsmBnC8596.png

选择要生成代码的包位置!生成代码结果:

 

wKioL1nPWEyh8bfrAAAcbmMgbZ0771.png

1.4    编写EndPoint

我们就不再像spring-ws官方那样再建一个Repository了,这里直接返回。需要注意PayloadRoot注解当中的namespacelocalPart需要和xsd中对应。

/**

 *

 * @项目名称:ws-server

 * @类名称:CountryEndPoint

 * @类描述:编写endpoint

 * @创建人:wyait

 * @创建时间:2017714上午11:02:49

 * @version

 */

@Endpoint

public class CountryEndPoint {

 

   privatestatic final String NAMESPACE_URI = "http://www.wyait.com/ws";

 

   @PayloadRoot(namespace= NAMESPACE_URI, localPart = "getCountryRequest")

   @ResponsePayload

   publicGetCountryResponse getCountry(

        @RequestPayloadGetCountryRequest request) {

      GetCountryResponseresponse = new GetCountryResponse();

      Countrypoland = new Country();

      poland.setName("Poland-"+ request.getName());

      poland.setCapital("Warsaw");

      poland.setCurrency(Currency.PLN);

      poland.setPopulation(38186860);

      response.setCountry(poland);

      returnresponse;

   }

}

 

1.5    Spring Boot整合web Service

/**

 *

 * @项目名称:ws-server

 * @类名称:WebServiceConfig

 * @类描述:spring boot整合web service

 * @创建人:wyait

 * @创建时间:2017714上午11:24:22

 * @version

 */

@EnableWs

@Configuration

public class WebServiceConfigextends WsConfigurerAdapter {

   @Bean

   publicServletRegistrationBean messageDispatcherServlet(

        ApplicationContextapplicationContext) {

      MessageDispatcherServletservlet = new MessageDispatcherServlet();

      servlet.setApplicationContext(applicationContext);

      servlet.setTransformWsdlLocations(true);

      returnnew ServletRegistrationBean(servlet, "/ws/*");

   }

 

   @Bean(name= "countries")

   publicDefaultWsdl11Definition defaultWsdl11Definition(

        XsdSchemacountriesSchema) {

      DefaultWsdl11Definitionwsdl11Definition = new DefaultWsdl11Definition();

      wsdl11Definition.setPortTypeName("CountriesPort");

      wsdl11Definition.setSchema(countriesSchema);

      returnwsdl11Definition;

   }

 

   @Bean

   publicXsdSchema countriesSchema() {

      returnnew SimpleXsdSchema(

           newClassPathResource("schema/countries.xsd"));

   }

}

 

到这里spring-ws的所有配置和工作都已经完成了,上面的DefaultWsdl11Definitionid默认就是发布的ws的访问路径。

 

1.6    启动项目

启动后访问 http://localhost:8080/ws/countries.wsdl 发现web service已经成功发布了。

 

wKiom1nPWJuRaXmkAADfq94uGXg010.png

 

这里要注意一下spring-ws发布的webservice是以后缀.wsdl访问的,跟传统的?wsdl不大一样,也看过它的源码,发现是在判断后缀时写死的,所以没办法配置修改了。

 

还有就是spring-ws实际上把发布wsdl和真正的服务实现Endpoint分开了,如果你的Endpoint不正确,很可能会出现浏览器访问.wsdl地址看起来正常而客户端调用却出现Not Found 404的错误。

 

2      web Service客户端

前面我们已经整合spring-ws实现了webservice的服务端:Spring Boot整合spring-ws开发web service客户端

 

接下来就是实现客户端进行调用了。

 

新建:ws-client(项目源码:https://git.oschina.net/wyait/springboot1.5.4.git

2.1    添加依赖

<dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-ws</artifactId>

        <version>1.4.5.RELEASE</version>

      </dependency>

      <dependency>

        <groupId>wsdl4j</groupId>

        <artifactId>wsdl4j</artifactId>

      </dependency>

 

 

服务端由一个xsd文件开始,客户端则是由一个wsdl文件开始。

 

获取wsdl文件也十分简单,用浏览器访问webservice地址,然后另存为即可。当然也可以直接用url地址来生成代码。

方式一:本地另存:

完整的wsdl文件如下:

<wsdl:definitionsxmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"

   xmlns:sch="http://www.wyait.com/ws"xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"

   xmlns:tns="http://www.wyait.com/ws"targetNamespace="http://www.wyait.com/ws">

   <wsdl:types>

      <xs:schemaxmlns:xs="http://www.w3.org/2001/XMLSchema"

        elementFormDefault="qualified"targetNamespace="http://www.wyait.com/ws">

        <xs:elementname="getCountryRequest">

           <xs:complexType>

              <xs:sequence>

                 <xs:elementname="name" type="xs:string" />

              </xs:sequence>

           </xs:complexType>

        </xs:element>

        <xs:elementname="getCountryResponse">

           <xs:complexType>

              <xs:sequence>

                 <xs:elementname="country" type="tns:country" />

              </xs:sequence>

           </xs:complexType>

        </xs:element>

        <xs:complexTypename="country">

           <xs:sequence>

              <xs:elementname="name" type="xs:string" />

              <xs:elementname="population" type="xs:int" />

              <xs:elementname="capital" type="xs:string" />

              <xs:elementname="currency" type="tns:currency" />

           </xs:sequence>

        </xs:complexType>

        <xs:simpleTypename="currency">

           <xs:restrictionbase="xs:string">

              <xs:enumerationvalue="GBP" />

              <xs:enumerationvalue="EUR" />

              <xs:enumerationvalue="PLN" />

           </xs:restriction>

        </xs:simpleType>

      </xs:schema>

   </wsdl:types>

   <wsdl:messagename="getCountryResponse">

      <wsdl:partelement="tns:getCountryResponse" name="getCountryResponse"></wsdl:part>

   </wsdl:message>

   <wsdl:messagename="getCountryRequest">

      <wsdl:partelement="tns:getCountryRequest"name="getCountryRequest"></wsdl:part>

   </wsdl:message>

   <wsdl:portTypename="CountriesPort">

      <wsdl:operationname="getCountry">

        <wsdl:inputmessage="tns:getCountryRequest"name="getCountryRequest"></wsdl:input>

        <wsdl:outputmessage="tns:getCountryResponse"name="getCountryResponse"></wsdl:output>

      </wsdl:operation>

   </wsdl:portType>

   <wsdl:bindingname="CountriesPortSoap11" type="tns:CountriesPort">

      <soap:bindingstyle="document"

        transport="http://schemas.xmlsoap.org/soap/http"/>

      <wsdl:operationname="getCountry">

        <soap:operationsoapAction="" />

        <wsdl:inputname="getCountryRequest">

           <soap:bodyuse="literal" />

        </wsdl:input>

        <wsdl:outputname="getCountryResponse">

           <soap:bodyuse="literal" />

        </wsdl:output>

      </wsdl:operation>

   </wsdl:binding>

   <wsdl:servicename="CountriesPortService">

      <wsdl:portbinding="tns:CountriesPortSoap11"name="CountriesPortSoap11">

        <soap:address/>

      </wsdl:port>

   </wsdl:service>

</wsdl:definitions>

 

方式二:jaxb2插件配置生成wsdl文件

跟服务端根据xsd来生成代码类似,客户端同样可以根据wsdl来生成代码。maven插件依赖:

<plugin>

           <groupId>org.jvnet.jaxb2.maven2</groupId>

           <artifactId>maven-jaxb2-plugin</artifactId>

           <version>0.12.3</version>

           <executions>

              <execution>

                 <goals>

                    <goal>generate</goal>

                 </goals>

              </execution>

           </executions>

           <configuration>

              <schemaLanguage>WSDL</schemaLanguage>

              <generatePackage>com.wyait.ws.domain</generatePackage>

              <generateDirectory>${basedir}/src/main/java</generateDirectory>

              <schemas>

                 <schema>

                    <fileset>

                      <!--Defaults to schemaDirectory. -->

                       <directory>${basedir}/src/main/resources/schema</directory>

                      <!--Defaults to schemaIncludes. -->

                      <includes>

                         <include>*.wsdl</include>

                      </includes>

                      <!--Defaults to schemaIncludes -->

                      <!--<excludes>-->

                      <!--<exclude>*.xs</exclude>-->

                      <!--</excludes>-->

                    </fileset>

                    <!--<url>http://localhost:8080/ws/countries.wsdl</url>-->

                 </schema>

              </schemas>

           </configuration>

        </plugin>

配置完,install将生成客户端代码。这里生成的代码跟我们前面发布的服务端代码应该是一样的,当然包名可能不同这个由自己指定。

 

在生成代码的同时会生成META-INF文件夹,这个可以移到resources目录下或者直接删除都没有关系。生成后的项目结构图:

wKioL1nPWGWSZEYDAAA60ofoGdM026.png

 

2.2    编写ws客户端

编写ws 客户端代码:

public class WsClient extendsWebServiceGatewaySupport {

   publicGetCountryResponse getCountry(String name) {

      GetCountryRequestrequest = new GetCountryRequest();

      request.setName(name);

      GetCountryResponseresponse = (GetCountryResponse) getWebServiceTemplate()

           .marshalSendAndReceive(

                 "http://http://127.0.0.1:9111/ws/countries.wsdl",

                 request);

      returnresponse;

   }

}

 

2.3    spring boot配置ws客户端

编写完一切代码之后,同样需要配置到spring boot才行,ContextPath指定刚才生成代码所在的包名,它会到该包下去寻找相应的类自动进行数据转换:

@Configuration

public class WSConfig {

   @Bean

   publicJaxb2Marshaller marshaller() {

      Jaxb2Marshallermarshaller = new Jaxb2Marshaller();

      marshaller.setContextPath("com.wyait.ws.domain");

      returnmarshaller;

   }

 

   @Bean

   publicWsClient wsClient(Jaxb2Marshaller marshaller) {

      WsClientclient = new WsClient();

      client.setDefaultUri("http://127.0.0.1:9111/ws/countries.wsdl");

      client.setMarshaller(marshaller);

      client.setUnmarshaller(marshaller);

      returnclient;

   }

}

 

2.4    编写controller

使用了RestController,直接将调用ws返回的数据用json格式输出到页面。

@RestController

public class IndexController {

    @Autowired

    private WsClient wsClient;

    @RequestMapping("callws")

    public Object callWs() {

        GetCountryResponse response =wsClient.getCountry("hello");

        return response.getCountry();

    }

}

 

端口改为:9112 避免和服务端端口9111冲突

 

启动,访问:http://127.0.0.1:9112/callws

wKiom1nPWLTgKNS3AAAI6JUg9JI968.png

 

回顾1.6章节末尾:

“还有就是spring-ws实际上把发布wsdl和真正的服务实现Endpoint分开了,如果你的Endpoint不正确,很可能会出现浏览器访问.wsdl地址看起来正常而客户端调用却出现Not Found 404的错误。”

 

排查ws服务端endpoint代码,没问题。是包命名的时候,单词写错了:

wKiom1nPWLzjay8iAABwAvj0AqY160.png

wyati改成:wyait。启动,访问:http://127.0.0.1:9112/callws

wKioL1nPWH-j8Pt4AAAGhicN8UA744.png

 



本文转自 wyait 51CTO博客,原文链接:http://blog.51cto.com/wyait/1970033,如需转载请自行联系原作者

相关文章
|
21天前
|
Java 应用服务中间件 Maven
SpringBoot 项目瘦身指南
SpringBoot 项目瘦身指南
38 0
|
1月前
|
Java 数据处理
【十二】springboot整合WebService
【十二】springboot整合WebService
41 0
|
2天前
|
XML Java C++
【Spring系列】Sping VS Sping Boot区别与联系
【4月更文挑战第2天】Spring系列第一课:Spring Boot 能力介绍及简单实践
23 0
【Spring系列】Sping VS Sping Boot区别与联系
|
1月前
|
Java
【十三】springboot整合WebService关于传参数
【十三】springboot整合WebService关于传参数
17 0
|
2月前
|
XML 监控 druid
【Java专题_02】springboot+mybatis+pagehelper分页插件+druid数据源详细教程
【Java专题_02】springboot+mybatis+pagehelper分页插件+druid数据源详细教程
|
3月前
|
Java
springboot项目打包瘦身
springboot项目打包瘦身
|
4月前
|
Java 数据库连接 Apache
SpringBoot整合CXF实现WebService
SpringBoot整合CXF实现WebService
123 0
|
5月前
|
Java 测试技术
Springboot集成JUnit5优雅进行单元测试
Springboot集成JUnit5优雅进行单元测试
|
9月前
|
Java Maven
【Springboot】创建boot工程spring-boot-maven-plugin报红、出错_解决方案
【Springboot】创建boot工程spring-boot-maven-plugin报红、出错_解决方案
313 0
|
9月前
|
Java 容器
springboot中简单创建webservice服务
不添加配置类也可以在springboot的启动类了里面发布服务,但是那样的话就不是ioc托管的了,在服务里面就不能注入其他IOC容器里面的对象