`
chnic
  • 浏览: 225891 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

利用AXIS开发Webservice(四) —— 如何抛出自定义异常

阅读更多

今天进入AXIS之四,如何抛出一个你的自定义异常。本来想连传文件一起介绍的。后来感觉一篇blog里太多的内容也不太好,看起来太辛苦,还是慢慢来,废话不多进入正题。

 

上一篇介绍了如果在Server和Client端传递一个自己的对象。有些人也许会问传递异常行不行?答案是可以。只不过传递异常的配置要稍微复杂一些。空口无凭,我还是用点代码来说明。今天的例子稍微复杂点,用一下数据库(MySQL)。首先创建表和输入测试数据。

create table users(id integer primary key, name varchar(20) not null);
 
insert into users values(1, 'Lincoln'),(2, 'Michael'),(4, 'Mahone'),(6, 'Sara');

 

一个user表,4条记录。等会我们client段会发送一个SOAP request给server段,之后server段返回客户要的数据,如果没有则抛出一个自定义异常。表建立完成之后来编写JavaBean。

package com.chnic.bean;

public class UserBean implements java.io.Serializable{

	private static final long serialVersionUID = 1L;
	private int id;
	private String name;
	
	public UserBean(){
		
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

 

Bean有两个属性,Id和Name。client会根据ID来取要的Name。编写完Bean之后我们来编写Customer Exception的代码。

package com.chnic.exception;

import java.rmi.RemoteException;

public class NoSuchUserException extends RemoteException {

	private String errorMessage = "No such user: ";
	private int id;
	private static final long serialVersionUID = 1L;

	public NoSuchUserException() {
	}

	public void printErrorMessage(){
		System.out.println(errorMessage + id);
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}
}

 

NoSuchUserException这个类会记录在数据库没有相应数据的ID的值,然后返回给Client。值得注意的是,因为这个是个远程异常。所以要继承RemoteException这个类。两个要transfer的Bean完成之后。我们来编写Service Ojbect的代码。

package com.chnic.webservice;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.chnic.bean.UserBean;
import com.chnic.exception.NoSuchUserException;
import java.sql.DriverManager;

public class CheckUserInfo {
	private String url = "jdbc:mysql://localhost:3306/test";
	private String user = "root";
	private String password = "root";
	
	
	public CheckUserInfo(){	
		
	}
	
	public Connection getConn(){
		try {
			Class.forName("com.mysql.jdbc.Driver");
			return DriverManager.getConnection(url, user, password);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public UserBean checkUser(int id) throws NoSuchUserException{
		Connection conn = null;
		try {
			conn = this.getConn();
			PreparedStatement statement = 
				conn.prepareStatement("select * from users where id = ?");
			statement.setInt(1, id);
			ResultSet rs = statement.executeQuery();
			boolean flag = false;
			UserBean user = null;
			 
			while(rs.next()){
				flag = true;
				user = new UserBean();
				user.setId(id);
				user.setName(rs.getString(2));
			}
			rs.close();
			if(flag)
				return user;
			else{
				NoSuchUserException userException = new NoSuchUserException();
				userException.setId(id);
				
				throw userException;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally{
			this.closeConn(conn);
		}
		return null;
	}
	
	public void closeConn(Connection conn){	
		try {
			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}
 

因为是Demo代码,代码写的比较粗糙,反正就是为了个演示。大家能看出来效果就好了。代码很简单,接收到一个id,然后在数据库里做匹配。如果找到匹配的了返回那个userbean,如果没找到就throw一个Exception出去。在这里多嘴一句。传递的Bean赋值的时候一定要用setXXX方法,不能用构造函数传递,否则传递过去之后属性值会丢失。 你编写的那个Bean一定要严格遵循JavaBean规范。  

之后我们来看WSDD发布文件。比起之前我们看到的WSDD文件,这次的稍微有点点复杂。

 

<deployment xmlns="http://xml.apache.org/axis/wsdd/" 
	xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
    
    <service name="AxisExceptionTest" provider="java:RPC">
       	<namespace>http://faults.samples</namespace>
        <parameter name="className" value="com.chnic.webservice.CheckUserInfo"/>
        <parameter name="allowedMethods" value="checkUser"/>
        <parameter name="scope" value="Session"/>
        
        <operation name="checkUser" 
        		   qname="operNS:checkUser" 
        		   xmlns:operNS="getSingleUser" 
        		   returnQName="getUserReturn" 
        		   returnType="rtns:User" 
        		   xmlns:rtns="http://faults.samples" >
        		   
       		<parameter name="id" type="tns:int" 
       			xmlns:tns="http://www.w3.org/2001/XMLSchema"/>     		
       		<fault name="NoSuchEmployeeFault" 
       			   qname="fns:fault" 
       			   xmlns:fns="http://faults.samples" 
       			   class="samples.faults.NoSuchEmployeeFault" 
       			   type="tns:NoSuchUserFault" 
       			   xmlns:tns="http://faults.samples"/>
    	</operation>
    	
        		   
        <typeMapping qname="myns:NoSuchUserFault" 
        	xmlns:myns="urn:CustomerFault"
            type="java:com.chnic.exception.NoSuchUserException"
            serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"
            deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory"
            encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
        
        <typeMapping qname="myns:User"
      		xmlns:myns="urn:CustomerBean"
       		type="java:com.chnic.bean.UserBean"
       		serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"
       		deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory"
       		encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
    </service>
</deployment>

 

首先不同的是多了个命名空间也就是namespace节点,等会测试代码中会看到用途。除了namespace之外还有operation这个节点和里面的parameter和fault子节点。先来介绍operation这个节点的属性。

 

name:操作名称或者方法名称,这个值会和你server发布的相关方法名匹配,所以要和方法名相同。

qname:针对这个operation的限定名。

xmlns:针对这个qname的命名空间也就是namespace。(不明白的可以看上一篇博文)

returnQName:这个元素节点所对应的方法返回出来对象的Qname。

returnType:返回类型,注意和下面的typemapping的qname比较。

 

parameter节点是这个operation指代的方法的参数,fault节点代表要这个方法要抛出的异常。异常也需要被mapping。下面的typemapping做的也是这样的事情。这两个元素的节点的属性和operation都是类似,对以一下大概就知道什么意思了。在这里也不多解释了。现在来看测试代码。

 

package com.chnic.test;

import java.rmi.RemoteException;

import javax.xml.namespace.QName;
import javax.xml.rpc.Call;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceException;
import javax.xml.rpc.ServiceFactory;
import javax.xml.rpc.encoding.TypeMapping;
import javax.xml.rpc.encoding.TypeMappingRegistry;

import org.apache.axis.encoding.ser.BeanDeserializerFactory;
import org.apache.axis.encoding.ser.BeanSerializerFactory;

import com.chnic.bean.UserBean;
import com.chnic.exception.NoSuchUserException;


public class TestException {

	public static void main(String[] args){
		String uri = "http://faults.samples";
		String serviceName = "EmployeeInfoService";
		ServiceFactory serviceFactory;
		String url = "http://localhost:8080/axis/services/AxisExceptionTest";
		try {
			serviceFactory = ServiceFactory.newInstance();
			QName serQ = new QName(uri, serviceName);
			Service service = serviceFactory.createService(serQ);
			
			TypeMappingRegistry registry = service.getTypeMappingRegistry();
	        TypeMapping map = registry.getDefaultTypeMapping();
	        	        
	        QName employeeQName = new QName("urn:CustomerBean", "User");
	        map.register(UserBean.class, employeeQName, 
	        	new BeanSerializerFactory(UserBean.class, employeeQName), 
	        	new BeanDeserializerFactory(UserBean.class, employeeQName));

	        QName faultQName = new QName("urn:CustomerFault", "NoSuchUserFault");
	        map.register(NoSuchUserException.class, faultQName, 
	        	new BeanSerializerFactory(NoSuchUserException.class, faultQName), 
	        	new BeanDeserializerFactory(NoSuchUserException.class, faultQName));
	                
	        Call call = service.createCall();
	        call.setTargetEndpointAddress(url);
	        
	        call.setOperationName( new QName(uri, "checkUser") );
	        Object obj = call.invoke(new Object[]{ new Integer(3)});
			UserBean user = (UserBean) obj;
			System.out.println(user.getName());
		    			
		} catch (ServiceException e) {
			e.printStackTrace();
		}catch(NoSuchUserException e){
			e.printErrorMessage();
		}catch (RemoteException e) {		
			e.printStackTrace();
		}
	}
}

 

看到第一个申明的uri了么?我们通过这个uri和service来取得对应的service。 之后我们用TypeMappingRegistry得到一个默认的TypeMapping。在map里面映射我们的bean。之后和往常的代码一样没有特别的。invoke唤起方法,返回UserBean,并打出UserBean的name。值得注意的是后面的catch部分,我们catch了一个我们自己申明的NoSuchUserException,抓住这个异常之后打出我们要的错误信息。

 

因为1 2 4 6在数据库里都是有对应的数值的,所以当我要查找ID为3个user的name的时候,service就会返回一个NoSuchUserException给我。之后在本地抓住这个exception之后,控制台打出了如下信息。

 

No such user: 3

 

如果输入的是1 2 4 6的话,则会返回user的名字。在这里就不测试了。各位自己可以试试。

 

分享到:
评论
2 楼 WLLT 2012-05-17  
我也是 估计少包
1 楼 hndl.ww 2009-06-30  
楼主:
客服端运行时候会出现:
javax.xml.rpc.ServiceException: Provider com.sun.xml.rpc.client.ServiceFactoryImpl not found
at javax.xml.rpc.FactoryFinder.newInstance(FactoryFinder.java:44)
at javax.xml.rpc.FactoryFinder.find(FactoryFinder.java:137)
at javax.xml.rpc.ServiceFactory.newInstance(ServiceFactory.java:58)
at com.chnic.test.TestException.main(TestException.java:28)

什么原因?

相关推荐

Global site tag (gtag.js) - Google Analytics