Spring学习笔记26

    技术2022-05-12  3

    Spring-WS集成()

    5.处理端点异常

    事情不会一帆风顺。传输的消息有可能不能转化成Java对象或消息根本就不是合法的XML,因此服务端点就有可能抛出一个异常——我们应该怎么处理它呢?

    如果处理消息时出现异常,我们需要向客户返回一个SOAP错误。不过,SOAP并不识别Java异常,而基于SOAPweb service通常都使用SOAP错误来表明失败。所以,我们需要将由web serviceSpring-WS抛出的java异常转化成SOAP错误。

    Spring-WS提供了SoapFaultMappingExceptionResolver,它负责处理在消息处理过程中出现的任何未捕获异常,并产生一个对应的SOAP错误返回给客户。在服务端,我们需要如下配置它:

    <bean id="endpointExceptionResolver"

        class="org.springframework.ws.soap.server.endpoint.

           SoapFaultMappingExceptionResolver">

        <property name="exceptionMappings">

           <props>

               <prop key="org.springframework.oxm.

                  UnmarshallingFailureException">

                  SENDER, Invaild message received</prop>

               <prop key="org.springframework.oxm.

                  ValidationFailureException">

                  SENDER, Invaild message received</prop>

           </props>

        </property>

        <property name="defaultFault" value="RECEIVER, Server error" />

    </bean>

    exceptionMappings属性配置了一个或多个SOAP错误与java异常的映射规则。每个<prop>的值都是一个Java异常,它都需要被转换成SOAP错误。每个<prop>值由两部分组成,第一部分表明错误类型;第二部分是描述错误的字符串。

           SOAP错误有两种类型:senderreceiverSender错误一般表示客户端的错误。Receiver错误表明是web service从客户端接收消息,但在处理消息时出错。

           举例来说,如果一个服务接收到一个不能被转换成java对象的XML消息,那么marshaler就会抛出org.springframework.oxm.UnmarshallingFailureExce-

    ption异常。因此发送方(sender)创建的该XML,所以这是一个sender错误。因此我们将该消息设置为“无效消息”。ValidateFailureException异常与之类似。

           任何没有显式地在exceptionMappings属性中配置映射的异常都将按defaultFault属性中定义的映射规则处理。上面的代码中,我们假定如果抛出的异常不匹配任何映射异常,那么我们视之为一个接收方(receiver)错误,所以,我们配置了接收方错误和错误信息:“server error”。

    6. 提供WSDL文件

           最后我们来看poker hand evaluation例子的WSDL文件的写法。我们已经创建了contract的数据部分作为XSD。那么现在我们选用EvaluateHandRequestEvaluateHandResponse作为组成web service消息的XML元素。选用这两个名字是有目的的,因为我们可以利用Spring-WS提供的惯例优先原则来自动地创建WSDL

           首先,我们需要配置Spring-WSDynamicWsdl11Definition,它会与MessageDispatcherServlet一同从XML Schema创建WSDL。这很容易实现,因为我们定义过XSD,下面展示如何配置DynamicWsdl11Definition

    <bean id="poker" class="org.springframework.ws.wsdl.wsdl11.

        DynamicWsdl11Definition">

        <property name="builder">

           <bean class="org.springframework.ws.wsdl.wsdl11.builder.

               XsdBasedSoap11Wsdl4jDefinitionBuilder" >

               <property name="schema" value="/PokerTypes.xsd" />

               <property name="portTypeName" value="Poker" />

               <property name="locationUri"

                  value="http://localhost:8080/Poker-WS/services" />

           </bean>

        </property>

    </bean>

    DynamicWsdl11Definition读取一个XSD(这里是PokerTypes.xsd),遍历schema文件来查找任何以RequestResponse名字结尾的元素定义,因为它认定RequestResponse后缀分别表明被发送到web service和从web service操作发出的消息,并在WSDL中创建一个相应的<wsdl:operation>元素。

           本例中,DynamicWsdl11Definition将会读取PokerTypes.xsd文件,并将EvaluateHandRequestEvaluateHandResponse元素分别作为EvaluateHand操作的输入和输出消息。因此,配置如下:

    <wsdl:portType name="Poker">

        <wsdl:operation name="EvaluateHand">

           <wsdl:input message="schema:EvaluateHandRequest"

               name="EvaluateHandRequest">

           </wsdl:input>

           <wsdl:output message="schema:EvaluateHandResponse"

               name="EvaluateHandResponse">

           </wsdl:output>

        </wsdl:operation>

    </wsdl:portType>

    值得注意的是,<wsdl:portType>由绑定在DynamicWsdl11DefinitionportTypeName属性中的值来命名。DynamicWsdl11Definition的最后一个属性是locationUri,它表明服务的地址。localhost表明它是运行在本机,/services表明它将匹配<servlet-mapping>中的配置。除此之外,我们还需要在web.xml中添加一个新的<servlet-mapping>,这样MessageDispatcherServlet才能提供WSDL。配置如下:

    <servlet-mapping>

           <servlet-name>poker</servlet-name>

           <url-pattern>*.wsdl</url-pattern>

    </servlet-mapping>

    到此为止,我们已经配置过了MessageDispatcherServlet来自动生成WSDL文件。但现在的问题是这个WSDL文件在哪里呢?

           自动创建的WSDLhttp://localhost:8080/Poker-WS/poker.wsdl处。因为MessageDispatcherServlet会被映射到*.wsdl,所以它会为每个匹配的请求尝试去创建WSDL。但是它怎么知道为poker servicepoker.wsdl上创建WSDL呢?答案就在于MessageDispatcherServlet遵循的惯例。值得注意的是,我们前面声明过DynamicWsdl11Definition bean来获取pokerID值。当MessageDispatcherServlet接收到一个请求时,它会在Spring context中寻找命名为pokerWSDL bean。本例中就是DynamicWsdl11Definition

    使用预定义WSDL

    DynamicWsdl11Definition大多数情况下都不需要你手动编写WSDL,但是在某些情况下你还是需要定制你自己的WSDL。本例中你需要手动创建WSDL并把它绑定到Spring中:

    <bean id="poker"

        class="org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition">

        <property name="wsdl" value="/PokerService.wsdl" />

    </bean>

    SimpleWsdl11Definition并不会创建WSDL,它只会通过wsdl属性提供WSDL

           预定义WSDL的唯一问题在于它是以静态方式定义的,这对于指定服务地址的WSDL就会是一个问题。例如,考虑下么的WSDL代码:

    <wsdl:service name="PokerService">

        <wsdl:port binding="tns:PokerBinding" name="PokerPort">

           <wsdlsoap:address

               location="http://localhost:8080/Poker-WS/services" />

        </wsdl:port>

    </wsdl:service>

    这里由http://localhost:8080/Poker-WS/services定义了服务的地址。如果你需要在另一个服务器上部署,那么这个地址就有可能需要变更。你可以每次手动地修改这个值,但是这个过程容易出错。

           但是MessageDispatcherServlet知道它被部署的地方,而且它也知道请求的URL。因此,你可以让MessageDispatcherServlet重写来完成这个地址值变更过程。你需要的就是设置名为transformWsdlLocations<init-param>true,例如:

    <servlet>

        <servlet-name>poker</servlet-name>

        <servlet-class>org.springframework.ws.transport.http.

           MessageDispatcherServlet</servlet-class>

        <init-param>

           <param-name>transformWsdlLocations</param-name>

           <param-value>true</param-value>

        </init-param>

    </servlet>

    transformWsdlLocation被设置成true时,MessageDispatcherServlet将重写SimpleWsdl11Definition提供的WSDL来匹配请求URL

    7. 部署服务

           我们已经配置了contract,编写了端点,并且所有的Spring-WS bean都已经准备就绪了。现在我们需要把这些打包成一个WAR包并将其部署。

           使用Spring-WS来构建一个web service只是它的一个方面。Spring-WS还提供了一个客户API。该API基于与服务器端相同的消息驱动机制。

     


    最新回复(0)