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错误!"异常;
以上两项都通过验证,服务端才继续为客户端提供服务。
?
?