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();
				}
				//创建QName
				String nameSpace = "http://ws.student.hqh.com";//wsdl的targetNamespace
				String 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" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
	    <property name="serviceInterface" 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" class="com.hqh.client.ws.controller.ClientController">
		<property name="studentWsService" 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);
//		}
//	}
	
	//自动注入
	@Resource
	private StudentService studentService;
	
	
	@Override
	public 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;

@Controller
public 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错误!"异常;

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

 

 

你可能感兴趣的:(exception)