前言

前两天就实现过web service,使用了CXF,请看这里:Spring boot 整合CXF开发web service.

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

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

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

这也太挫了,本人当然不能接受.既然spring能在WebSphere下正常运行,那么spring的组件能够成功运行的可能性相对较大.

研究考虑之后,决定选用spring-ws来实现web service.事实证明选择是正确的。项目地址:http://projects.spring.io/spring-ws

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

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

添加依赖

spring boot的工程,除了spring boot外还需要添加spring-ws和wsdl4j的依赖,当然后面生成代码还需要添加maven的jaxb2插件。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-ws</artifactId>
</dependency>
<dependency>
    <groupId>wsdl4j</groupId>
    <artifactId>wsdl4j</artifactId>
</dependency>

编写schema文件

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

下面是官方示例给出的countries.xsd,这里我们也以它为例,当然命名空间改掉了,因为等会jaxb2插件生成代码是以它来确定包名的:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.ktanx.com/ws"
        targetNamespace="http://www.ktanx.com/ws" elementFormDefault="qualified">

    <xs:element name="getCountryRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="name" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="getCountryResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="country" type="tns:country"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="country">
        <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="population" type="xs:int"/>
            <xs:element name="capital" type="xs:string"/>
            <xs:element name="currency" type="tns:currency"/>
        </xs:sequence>
    </xs:complexType>

    <xs:simpleType name="currency">
        <xs:restriction base="xs:string">
            <xs:enumeration value="GBP"/>
            <xs:enumeration value="EUR"/>
            <xs:enumeration value="PLN"/>
        </xs:restriction>
    </xs:simpleType>
</xs:schema>

添加maven的jaxb2插件来生成代码

jaxb2插件可以根据描述的xsd文件来帮我们生成相应的ws代码,具体配置如下:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
</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//schema</schemaDirectory>
        <outputDirectory>${project.basedir}/src/main/java</outputDirectory>
        <clearOutputDir>false</clearOutputDir>
    </configuration>
</plugin>

配置好插件然后install一下,这样web service需要的服务端代码就已经帮我们生成好了,根据上面的xsd,生成的代码在com.dexcoder.ws包下。

生成的代码

编写Endpoint

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

@Endpoint
public class CountryEndpoint {
    private static final String NAMESPACE_URI = "http://www.ktanx.com/ws";

    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
    @ResponsePayload
    public GetCountryResponse getCountry(@RequestPayload GetCountryRequest request) {
        GetCountryResponse response = new GetCountryResponse();

        Country poland = new Country();
        poland.setName("Poland-" + request.getName());
        poland.setCapital("Warsaw");
        poland.setCurrency(Currency.PLN);
        poland.setPopulation(38186860);
        response.setCountry(poland);
        return response;
    }
}

在spring boot中配置web service

在spring boot中配置spring-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 = "countries")
    public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
        DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
        wsdl11Definition.setPortTypeName("CountriesPort");
        wsdl11Definition.setSchema(countriesSchema);
        return wsdl11Definition;
    }

    @Bean
    public XsdSchema countriesSchema() {
        return new SimpleXsdSchema(new ClassPathResource("schema/countries.xsd"));
    }
}

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

启动项目

最后一步当然是启动项目了,这里依然使用spring boot的启动方式:

@SpringBootApplication
public class ApplicationStartup {

    public static void main(String[] args) {
        SpringApplication.run(ApplicationStartup.class);
    }
}

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

spring-ws-wsdl

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

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

下一篇将讲解如何实现客户端来调用这个web service,为什么要分开呢?因为客户端要根据wsdl生成相应的代码,如果放在一起这些代码都有了就演示不到这一步了。

你可能感兴趣的内容
Spring Boot中使用 MongoDB 3.0 收藏,4180 浏览
0条评论

selfly

交流QQ群:32261424
Owner