读书人

JAX与spring的无缝集成-增多Handler和

发布时间: 2013-08-16 14:29:57 作者: rapoo

JAX与spring的无缝集成---增加Handler和Exception(二)

客户端也使用spring集成JAX-WS。但是有一个问题需要处理!

想在SOAP消息中加入HEADER该怎样加入呢,使用Handler!

之前使用handler都是通过在实现类上使用注解@HandlerChain(file="handler-chain.xml")进行标注引入的

//声明handler的位置@HandlerChain(file="handler-chain.xml")public class StudentWSService    extends Service{...}

?

然后手动创建这个实现类的对象,这样自然能讲handler加入到程序运行逻辑中。

IStudentWSService iservice = new StudentWSService().getStudentServicePort();

?

?

但是,将JAX-WS与spring集成后,使用的实现类是由spring提供的一个代理来完成,这将如何做呢???

通过JaxWsPortProxyFactoryBean的最上层父类LocalJaxWsServiceFactory中的属性handlerResolver来定义!?

编写Handler

?

package com.hqh.student.ws.handler;import java.util.Set;import javax.xml.namespace.QName;import javax.xml.soap.SOAPBody;import javax.xml.soap.SOAPConstants;import javax.xml.soap.SOAPElement;import javax.xml.soap.SOAPEnvelope;import javax.xml.soap.SOAPException;import javax.xml.soap.SOAPHeader;import javax.xml.ws.handler.MessageContext;import javax.xml.ws.handler.soap.SOAPHandler;import javax.xml.ws.handler.soap.SOAPMessageContext;public class LicenseHandler implements SOAPHandler<SOAPMessageContext> {public void close(MessageContext ctx) {}public boolean handleFault(SOAPMessageContext ctx) {return false;}public boolean handleMessage(SOAPMessageContext context) {try {Boolean out = (Boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY);if(out) {System.out.println("message outing...");SOAPEnvelope soapEnv = context.getMessage().getSOAPPart().getEnvelope();SOAPBody soapBody = soapEnv.getBody();//获取当前在调用服务的哪个方法String localName = soapBody.getFirstChild().getLocalName();//System.out.println(localName);if(!"getStudent".equals(localName)) {return true;}//如果是getStudent,则加入头信息SOAPHeader soapHeader = soapEnv.getHeader();if(soapHeader==null) {soapHeader = soapEnv.addHeader();}//创建QNameString nameSpace = "http://ws.student.hqh.com";//wsdl的targetNamespaceString part = "license";//message的name,必须与wsdl中定义的一致String prefix = "ns";//前缀QName headerQName = new QName(nameSpace, part, prefix);//将QName加入Header,并设定值soapHeader.addHeaderElement(headerQName).setValue("admin");} else {System.out.println("message come back...");}return true;} catch (SOAPException e) {e.printStackTrace();}return false;}public Set<QName> getHeaders() {return null;}}

?

?

编写HandlerResolver

?

package com.hqh.student.ws.handler;import java.util.ArrayList;import java.util.List;import javax.xml.ws.handler.Handler;import javax.xml.ws.handler.HandlerResolver;import javax.xml.ws.handler.PortInfo;import org.springframework.stereotype.Service;import com.sun.xml.ws.util.JAXWSUtils;/** * 将新的HandlerList返回,由spring提供的代理服务进行调用 * 这样就达到了使用Handler的目的 * 怎样通过paramPortInfo获取到已有的Handler呢??? */@Service("soapHeaderHandler")public class SOAPHeaderHandler implements HandlerResolver  {private List<Handler> newHandlerList = null;public SOAPHeaderHandler() {newHandlerList = new ArrayList<Handler>();newHandlerList.add(new LicenseHandler());}public List<Handler> getHandlerChain(PortInfo paramPortInfo) {return newHandlerList;}}

?

?

?让spring注入handler到其代理服务中

在spring为JAX-WS提供的代理bean中配置Handler(关键),这样就能将Handler注入到代理对象中了!

?

<?xml version="1.0" encoding="UTF-8"?><beans  xmlns="http://www.springframework.org/schema/beans"        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:aop="http://www.springframework.org/schema/aop"    xmlns:tx="http://www.springframework.org/schema/tx"        xmlns:context="http://www.springframework.org/schema/context"        xmlns:ws="http://jax-ws.dev.java.net/spring/core"        xmlns:wss="http://jax-ws.dev.java.net/spring/servlet"        xsi:schemaLocation="http://www.springframework.org/schema/beans            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd           http://www.springframework.org/schema/context           http://www.springframework.org/schema/context/spring-context-3.0.xsd             http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd           http://jax-ws.dev.java.net/spring/core http://jax-ws.dev.java.net/spring/core/spring-jax-ws-core.xsd           http://jax-ws.dev.java.net/spring/servlet http://jax-ws.dev.java.net/spring/servlet/spring-jax-ws-servlet.xsd"><context:annotation-config/><context:component-scan base-package="com.hqh.client"/><!-- 声明需要被spring进行注解扫描 --><context:component-scan base-package="com.hqh.student.ws.handler"/><!-- 利用spring完成webservice服务的注入! --><!-- Accessing web services using JAX-WS --><bean id="wsService" value="com.hqh.student.ws.IStudentWSService"/>    <property name="wsdlDocumentUrl" value="http://localhost:9999/server/jaxws-spring?wsdl"/>    <property name="namespaceUri" value="http://ws.student.hqh.com"/>    <property name="serviceName" value="StudentWSService"/>    <property name="portName" value="studentServicePort"/>    <!-- 将处理头信息的Handler注入到JaxWsPortProxyFactoryBean中-->    <property name="handlerResolver" ref="soapHeaderHandler"></property>    </bean>        <!-- 依赖注入 --><bean id="client" ref="wsService"></property></bean>       </beans>

?

?

服务端增加异常类,如果调用服务端的getStudent()没有头信息或者头信息中的license错误,则抛出异常

package com.hqh.student.exception;/** * 处理webservice的异常最好继承Exception,而不是RuntimeException * 该Exception就是wsdl中新增的自定义Exception * @author lenovo * */public class StudentWsException extends Exception {public StudentWsException() {super();}public StudentWsException(String message, Throwable cause) {super(message, cause);}public StudentWsException(String message) {super(message);}public StudentWsException(Throwable cause) {super(cause);}}

?在wsdl中增加异常消息

<?xml version="1.0" encoding="UTF-8" standalone="no"?><wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"xmlns:tns="http://ws.student.hqh.com" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="StudentWSService"targetNamespace="http://ws.student.hqh.com"><!-- 指定schema --><wsdl:types><xsd:schema targetNamespace="http://ws.student.hqh.com"><xsd:include schemaLocation="student.xsd"/><!-- 增加头信息(for HEADER) --> <xsd:element name="license" type="xsd:string"/> <!-- 增加异常 --><xsd:element name="StudentWsException" type="tns:StudentWsException"></xsd:element><xsd:complexType name="StudentWsException"><xsd:sequence><xsd:element name="errorMsg" type="xsd:string"/></xsd:sequence></xsd:complexType></xsd:schema></wsdl:types><!-- 增加异常消息 --><wsdl:message name="StudentWsException"><wsdl:part name="fault" element="tns:StudentWsException"/></wsdl:message><!-- 为license创建新的message(for HEADER)  -->  <wsdl:message name="license">      <wsdl:part name="license" element="tns:license"></wsdl:part>  </wsdl:message>  <!-- 指定方法 --><wsdl:message name="getStudent"><wsdl:part element="tns:getStudent" name="parameters" /></wsdl:message><wsdl:message name="getStudentResponse"><wsdl:part element="tns:getStudentResponse" name="parameters" /></wsdl:message><wsdl:message name="list"><wsdl:part element="tns:list" name="parameters" /></wsdl:message><wsdl:message name="listResponse"><wsdl:part element="tns:listResponse" name="parameters" /></wsdl:message><wsdl:message name="listReward"><wsdl:part element="tns:listReward" name="parameters" /></wsdl:message><wsdl:message name="listRewardResponse"><wsdl:part element="tns:listRewardResponse" name="parameters" /></wsdl:message><!-- 指定接口 --><wsdl:portType name="IStudentWSService"><wsdl:operation name="getStudent"><wsdl:input message="tns:getStudent" /><wsdl:output message="tns:getStudentResponse" />                        <!-- 异常 -->      <wsdl:fault name="StudentWsException" message="tns:StudentWsException"></wsdl:fault></wsdl:operation><wsdl:operation name="list"><wsdl:input message="tns:list" /><wsdl:output message="tns:listResponse" /></wsdl:operation><wsdl:operation name="listReward"><wsdl:input message="tns:listReward" /><wsdl:output message="tns:listRewardResponse" /></wsdl:operation></wsdl:portType><!-- 指定接口中的方法的参数编码格式 --><wsdl:binding name="studentSOAP" type="tns:IStudentWSService"><soap:binding style="document"transport="http://schemas.xmlsoap.org/soap/http" /><wsdl:operation name="getStudent"><wsdl:input><!-- add方法的header中加入license消息 (for HEADER) -->  <soap:header use="literal" part="license" message="tns:license"/>  <soap:body use="literal" /></wsdl:input><wsdl:output><soap:body use="literal" /></wsdl:output>                        <!-- 异常 --><wsdl:fault name="StudentWsException"><soap:fault name="StudentWsException" use="literal"/></wsdl:fault></wsdl:operation><wsdl:operation name="list"><wsdl:input><soap:body use="literal" /></wsdl:input><wsdl:output><soap:body use="literal" /></wsdl:output></wsdl:operation><wsdl:operation name="listReward"><wsdl:input><soap:body use="literal" /></wsdl:input><wsdl:output><soap:body use="literal" /></wsdl:output></wsdl:operation></wsdl:binding><!-- 指定服务名称、端口、地址 --><wsdl:service name="StudentWSService"><wsdl:port binding="tns:studentSOAP" name="studentServicePort"><soap:address location="http://localhost:8080/student-web/ws/" /></wsdl:port></wsdl:service></wsdl:definitions>

?

服务端的接口和实现类抛出异常

@WebService(name = "IStudentWSService", targetNamespace = "http://ws.student.hqh.com")public interface IStudentWSService {    /**     *      * @param number     * @return     *     returns com.hqh.student.ws.Student     */    @WebMethod    @WebResult(name = "stu", targetNamespace = "")    @RequestWrapper(localName = "getStudent", targetNamespace = "http://ws.student.hqh.com")    @ResponseWrapper(localName = "getStudentResponse", targetNamespace = "http://ws.student.hqh.com")    public Student getStudent(        @WebParam(name = "number", targetNamespace = "")        String number,        @WebParam(name="license", header=true) String license) throws StudentWsException;

?

@WebService(endpointInterface="com.hqh.student.ws.IStudentWSService",serviceName="StudentWSService",portName="studentServicePort",targetNamespace="http://ws.student.hqh.com",wsdlLocation="/WEB-INF/wsdl/student.wsdl")//该对象交由spring管理,studentWsService即为该实现类在bean容器中的name@Component("studentWsService")public class StudentWSServiceImpl implements IStudentWSService{//private static final BeanFactory factory = new ClassPathXmlApplicationContext("beans.xml");//public StudentWSServiceImpl() {//if(studentService==null) {//studentService = factory.getBean(StudentService.class);//}//}//自动注入@Resourceprivate StudentService studentService;@Overridepublic Student getStudent(String number, String license) throws StudentWsException {//studentService = (StudentService) WebUtil.getBean(StudentService.class);//studentService = (StudentService) BeanFactoryUtil.getBean(StudentService.class);//根据license进行处理System.out.println("client send license:"+license);if(license==null || "".equals(license)) throw new StudentWsException("SOAP消息HEADER不能为空!");if(!license.equals("admin")) throw new StudentWsException("SOAP消息HEADER携带的license错误!");return studentService.getStudent(number);}

?

从新生成客户端的java文件,调用服务时捕获异常消息

package com.hqh.client.ws.controller;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import com.hqh.student.ws.IStudentWSService;import com.hqh.student.ws.Student;import com.hqh.student.ws.StudentWsException_Exception;@Controllerpublic class ClientController {/** * 容器初始化第一次,会调用setters进行注入,但是第2次开始,ClientController变为一个新的对象 * 导致studentWsService为NULL,所以,这里使用static来保存第一次初始化好webservice接口的代理对象 * 这里是使用配置文件的方式利用spring提供的配置示例进行注入的 * 用注解注入又该怎样做呢? */private static IStudentWSService studentWsService;//通过setters方法进行注入!public void setStudentWsService(IStudentWSService wsService) {studentWsService = wsService;}@RequestMapping(value="/getStudent",method=RequestMethod.GET)public String getStudent() {return "index";}@RequestMapping(value="/getStudent",method=RequestMethod.POST)public String getStudent(String number,Model model) {Student stu = null;try {stu = studentWsService.getStudent(number);} catch (StudentWsException_Exception e) {//调用服务如果发生异常,将异常显示到页面中model.addAttribute("error", e.getMessage());return "index";}if(stu==null) {model.addAttribute("error", "不存在!");} else {model.addAttribute(stu);}return "index";}}

?

客户端调用getStudent()

如果没有传递Header,抛出“SOAP消息HEADER不能为空!”异常;

如果传递了Header,但license不是"admin",抛出"SOAP消息HEADER携带的license错误!"异常;

以上两项都通过验证,服务端才继续为客户端提供服务。

?

?

读书人网 >编程

热点推荐