今天進入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');
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;
- }
- }
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;
- }
- }
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();
- }
- }
- }
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>
<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();
- }
- }
- }
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的名字。在這里就不測試了。各位自己可以試試。