對于 Hessian 的基本介紹,可以參見 Hessian 簡介。在應(yīng)用程序的實際開發(fā)中,情況往往比較復(fù)雜,但是 Hessian 是一個功能比較強(qiáng)大的 Web service 框架,提供了諸如訪問受到 BASIC 認(rèn)證保護(hù)的服務(wù)、傳遞Date、List、Map等常用類型以及對象等復(fù)雜數(shù)據(jù)類型的功能。
1. 使用 Basic 認(rèn)證保護(hù) Web 服務(wù)
如果沒有認(rèn)證機(jī)制,那么能夠連接到 Web service 服務(wù)器上的客戶端都有可能訪問到 Web 服務(wù)??梢岳?Web 服務(wù)器的安全機(jī)制將 Web service 配置成 Basic 認(rèn)證模式,這樣訪問 Web service 的客戶端都必須提供用戶名和密碼才能訪問。就 Tomcat 來說,對于在 Hessian 簡介中介紹的應(yīng)用,可以在 web.xml 增加一下內(nèi)容來設(shè)置 hello 服務(wù)使用安全認(rèn)證機(jī)制:
<!-- Define reference to the user database for looking up roles -->
<resource-env-ref>
<description></description>
<resource-env-ref-name>users</resource-env-ref-name>
<resource-env-ref-type>org.apache.catalina.UserDatabase</resource-env-ref-type>
</resource-env-ref>
<!-- Define a Security Constraint on this Application -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Hessian Example</web-resource-name>
<url-pattern>/hello</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>tomcat</role-name>
</auth-constraint>
</security-constraint>
<!-- Define the Login Configuration for this Application -->
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Hessian Example</realm-name>
</login-config>
<!-- Security roles referenced by this web application -->
<security-role>
<description></description>
<role-name>tomcat</role-name>
</security-role>
這樣,只有屬于 tomcat 這個角色的用戶才能訪問 hello 服務(wù)。
相應(yīng)地,在編寫 Hessian 客戶端程序的時候,就必須提供用戶名和密碼,才能訪問。HessianProxyFactory 提供了 setUser() 和 setPassword() 兩個方法用來設(shè)置用戶名和密碼。對于上述應(yīng)用,應(yīng)該在代碼中添加:
factory.setUser("tomcat");
factory.setPassword("tomcat");
2. 讓 Web service 返回數(shù)組
在 Basic.java 接口中增加方法:
public String[] getNames();
在 BasicService.java 中實現(xiàn)該方法:
public String[] getNames() {
return new String[] { "Apache", "Tomcat", "Hessian" };
}
在客戶端可以這樣訪問:
String[] names = basic.getNames();
for(int i = 0; i < names.length; i++)
{
System.out.println(names[i]);
}
3. 讓 Web service 返回一個對象
(1)不成功的做法
創(chuàng)建一個簡單 JavaBean 類 Person,只包含三個屬性:
package example;
import java.util.Date;
public class Person{
private int id = 0;
private String name = "";
private Date birthday = null;
public Person(int id, String name, Date birthday) {
super();
this.id = id;
this.name = name;
this.birthday = birthday;
}
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;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
在接口中定義:
public Person getPerson(int id);
在服務(wù)類中實現(xiàn):
public Person getPerson(int id) {
Person p = null;
switch (id) {
case 1:
p = new Person(1, "Tom", new java.util.Date(1980, 1, 1));
break;
case 2:
p = new Person(2, "Rose", new java.util.Date(1981, 1, 1));
break;
default:
break;
}
return p;
}
客戶端程序
Person p = basic.getPerson(1);
System.out.println(p.getName());
運行客戶端程序,拋出異常:
Exception in thread "main" com.caucho.hessian.client.HessianConnectionException: 500: java.io.IOException: Server returned HTTP response code: 500 for URL: http://127.0.0.1:8080/htest/hello
at com.caucho.hessian.client.HessianProxy.invoke(HessianProxy.java:202)
at $Proxy0.getPerson(Unknown Source)
at example.BasicClient.main(BasicClient.java:25)
查看服務(wù)器日志,得到異常信息:
java.lang.IllegalStateException: Serialized class example.Person must implement java.io.Serializable
at com.caucho.hessian.io.SerializerFactory.getDefaultSerializer(SerializerFactory.java:262)
at com.caucho.hessian.io.SerializerFactory.getSerializer(SerializerFactory.java:234)
at com.caucho.hessian.io.Hessian2Output.writeObject(Hessian2Output.java:406)
...
異常提示 example.Person 必須實現(xiàn) java.io.Serializable 接口。
(2)Serializable 和序列化
對于簡單數(shù)據(jù)類型,如int, double, char,數(shù)組等,以及常用的一些類型,如String,java.util.Date,List, Map等,Hessian 本身對其進(jìn)行了特殊處理,也就是 Hessian 對其進(jìn)行了序列化操作,但是 Hessian 不可能了解其他的類以及在您的應(yīng)用程序中使用的那些類。對于這些類,Hessian 則要求這些類本身能夠被序列化,也就是要求這些必須實現(xiàn) Serializable 接口。
(3)正確的做法
讓 Person 實現(xiàn) Serializable 接口,則 Person.java 應(yīng)該被修改成:
package example;
import java.io.Serializable;
import java.util.Date;
public class Person implements Serializable{
private int id = 0;
private String name = "";
private Date birthday = null;
...
重新啟動 Web 服務(wù)器,就可以成功運行客戶端程序了。
4. 讓 Web service 返回一個包含 Person 對象 List
在 Basic.java 接口中增加方法:
public List<Person> listPersons();
在 BasicService.java 中實現(xiàn)該方法:
public List<Person> listPersons() {
List<Person> list = new ArrayList<Person>();
list.add(new Person(1, "Tom", new java.util.Date(1980, 1, 1)));
list.add(new Person(2, "Rose", new java.util.Date(1981, 1, 1)));
return list;
}
在客戶端可以這樣訪問:
List<Person> list = basic.listPersons();
System.out.println(list.size());
(###)