前言:
近日着手研究了一下Hessian的rmi方案,因为客户端是多种移动终端平台,本来想采用传说中的phprpc(hprose?)的,但看了下官方的文档,发现没有object-c的版本,故而放弃。
跟着hessian 的官方例子走,跑起来是没有问题的,但我在试着跟spring整合的时候,出了不少的问题。记录一下,方便自己以及路人,呵呵。
环境说明:
- spring version 3.0 RELEASE.
- Hessian version 4.0.7 WHATEVER.
- JEE version 2.5
实现步骤:
- 配置 web.xml ,添加对spring-web中 DispatcherServlet的定义.具体如下:
Xml代码
- <servlet>
- <servlet-name>test-remote</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>/WEB-INF/config/test-remote.xml</param-value>
- </init-param>
- <load-on-startup>4</load-on-startup>
- </servlet>
-
- <servlet-mapping>
- <servlet-name>test-remote</servlet-name>
- <url-pattern>/remote/*</url-pattern>
- </servlet-mapping>
Tips: A. 很多网友都说一定要在WEB-INF下面放入跟servlet-name相对应的 test-remote-servlet.xml 配置文件,实际上是不一定要那么处理的。如果指定了 contextConfigLocation的话,就可以解决这个问题。意味着spring不会强制要求你配置文件的位置。 B. DispatcherServlet是可以配置多个的,我这里还有一个test-local,mapping着 "/" 路径,他们之间并不会影响。当然可以单纯的配置多个 servlet-mapping.我只是想验证一下,结果说明确实是可以的。
- 传输对象类Space 的定义:
Java代码
- package test.remote.dto;
-
- import java.io.Serializable;
- import java.util.Date;
-
- /**
- * Space data transfer object.
- * @author gogo
- *
- */
- public class Space implements Serializable{
-
- /**
- * auto generated serialVersionUid.
- */
- private static final long serialVersionUID = 5632812127919571530L;
-
- /** public space name for people in the space.*/
- private String publicName;
- private String privateName;
- private boolean isActive;
- private Date lastUpdatedTime;
-
- /**
- * setter & getter
- */
-
- @Override
- public String toString() {
- StringBuilder buffer = new StringBuilder("Space:");
- buffer.append("public name:").append(publicName).append(", ");
- buffer.append("private name:").append(privateName).append(", ");
- buffer.append("is actived:").append(isActive).append(", ");
- buffer.append("lastUpdatedTime:").append(lastUpdatedTime.getTime());
- return buffer.toString();
- }
- }
- 服务接口的定义如下:
package test.remote.service;
Java代码
- import java.util.List;
-
- import test.remote.dto.Space;
-
- /**
- *
- * @author gogo
- *
- */
- public interface SpaceService {
-
- List showSpaceNames(); //返回名字集合
-
- Space findSpace(String id);//找到空间名字
-
- boolean updateSpaceName(String name); //更新空间名字
-
- }
- 服务接口实现类:
package test.remote.service.impl;
Java代码
- import java.util.ArrayList;
- import java.util.Date;
- import java.util.List;
-
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.springframework.remoting.caucho.HessianServiceExporter;
-
- import test.remote.dto.Space;
- import test.remote.service.SpaceService;
-
- /**
- * 这个是一个远程接口的测试实现<br>
- * 该接口会由spring的 {@link HessianServiceExporter}以Http服务的形式暴露.<br>
- * 客户端会依赖Hessian实现
- * @see HessianServiceExporter
- * @author gogo
- *
- */
- public class SpaceServiceImpl implements SpaceService{
-
- private static final Log log = LogFactory.getLog(SpaceServiceImpl.class);
-
- private Space createSpace() {
- Space space = new Space();
- space.setPublicName("roosher-space");
- space.setPrivateName("my-private-room");
- space.setActive(true);
- space.setLastUpdatedTime(new Date());
- return space;
- }
-
- public Space findSpace(String id) {
- // TODO Auto-generated method stub
- log.debug("find space id is :" + id);
- return createSpace();
- }
-
- public List showSpaceNames() {
- // TODO Auto-generated method stub
- List names = new ArrayList<String>();
- for (int i = 0; i < 10; i++) {
- names.add("Hello space "+ i);
- }
- return names;
- }
-
- public boolean updateSpaceName(String name) {
- // TODO Auto-generated method stub
- log.debug("updated space name : " + name );
- return true;
- }
-
- }
- test-remote.xml的内容:
Xml代码
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www./schema/beans"
- xmlns:context="http://www./schema/context"
- xmlns:p="http://www./schema/p"
- xmlns:xsi="http://www./2001/XMLSchema-instance"
- xsi:schemaLocation="http://www./schema/beans
- http://www./schema/beans/spring-beans-3.0.xsd
- http://www./schema/context
- http://www./schema/context/spring-context-3.0.xsd">
- <bean
- class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"
- p:order="1"></bean>
-
- <bean id="spaceService" class="test.service.impl.SpaceServiceImpl">
- </bean>
-
- <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter">
- </bean>
-
- <bean name="/SpaceHessian"
- class="org.springframework.remoting.caucho.HessianServiceExporter"
- p:serviceInterface="test.remote.service.SpaceService"
- p:service-ref="spaceService">
- </bean>
-
- <bean name="/SpaceBurlap"
- class="org.springframework.remoting.caucho.BurlapServiceExporter"
- p:serviceInterface="test.remote.service.SpaceService"
- p:service-ref="spaceService">
- </bean>
-
- </beans>
Tips: A. BeanNameUrlHandlerMapping 属性中的 p:order="1",可以不用配置.避免跟自己的冲突. B. HttpRequestHandlerAdapter 在这里面非常关键,没有它可能会出现这种错误: -- No adapter for handler Does your handler implement a supported interface like Controller ? HttpRequestHandlerAdapter它的作用就是让spring-mvc放出权限给下面的Exporter自己处理整个HTTP 流程.毕竟HessianServiceExporter也是实现的HttpRequestHandler
- 客户端的两种实现:
A. 就是基于spring的实现,采用org.springframework.remoting.caucho.HessianProxyFactoryBean实现,相关配置如下:
Java代码
- <bean id="spaceServiceHessian"
- class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
- <property name="serviceUrl"
- value="http://localhost:8080/test/remote/SpaceHessian" />
- <property name="serviceInterface" value="test.remote.service.SpaceService" />
- </bean>
-
- <bean id="spaceServiceBurlap"
- class="org.springframework.remoting.caucho.BurlapProxyFactoryBean">
- <property name="serviceUrl"
- value="http://localhost:8080/test/remote/SpaceBurlap" />
- <property name="serviceInterface" value="test.remote.service.SpaceService" />
- </bean>
注意到里面的URL了没? 其中 http://localhost:8080/test/remote/SpaceHessian 的/SpaceHessian 对应的是之前在remote-test.xml中配置的<bean name="/SpaceHessian"> </bean>的URI.
然后通过spring获取上下文之后,就可以直接注入 SpaceService service = context.getBean("spaceServiceBurlap");
B . 就是基于Hessian 自己提供的客户端,这里展示的是Java版本.
-
Java代码
- package test.remote;
-
- import java.net.MalformedURLException;
- import java.util.List;
-
- import com.caucho.hessian.client.HessianProxyFactory;
- import test.remote.dto.Space;
- import test.remote.service.SpaceService;
-
- /**
- * 连接客户端。测试时要注意 url的ip地址.
- * @see Space
- * @author gogo
- *
- */
- public class SpaceClient {
-
- public static void main(String[] args) {
- String url = "http://192.168.0.9:8080/test/remote/SpaceHessian";
- HessianProxyFactory factory = new HessianProxyFactory();
- try {
- SpaceService spaceService = (SpaceService) factory.create(
- SpaceService.class, url);
- System.out.println(spaceService.findSpace("testid"));
- System.out.println(spaceService.updateSpaceName("whatever"));
-
- List spaceNames = spaceService.showSpaceNames();
- System.out.println("\r\nGet space names:");
- for (int i = 0; i < spaceNames.size(); i++) {
- System.out.print(spaceNames.get(i) + ", ");
- }
- System.out.println();
- System.out.println("space names list finished");
- } catch (MalformedURLException e) {
- e.printStackTrace();
- }
- }
- }
如果后台没有什么太大的问题,直接跑起来就可以测试了。
- 测试结果:
Java代码
- Space:public name:roosher-space, private name:my-private-room, is actived:true,
- lastUpdatedTime:1282196778538
- true
-
- Get space names:
- Hello space 0, Hello space 1, Hello space 2, Hello space 3, Hello space 4, Hello space 5
- , Hello space 6, Hello space 7, Hello space 8, Hello space 9,
- space names list finished
- Cheers! 第一次认真的写博.但愿对大家有所帮助 。
分享到:
评论
gogomarine 写道
lvff1314 写道
跟你遇到基本相同的情况,移动多平台访问,最初决定使用PHPRPC,后来发现没有Objective-c,而所谓的hprose又不提供下载,故转道hessian,目前我用的最新的4.0.7,server端同样使用的spring进行hessian服务发布,但是遇到了一个比较尴尬的问题,我发现hessian在server端获取session比较困难,仔细查看client源码发现没有cookie机制,后对源码进行扩展增加了对response的header “Set-Cookie”的处理,但仍无效果。。。而且发现,spring通过自己的mvc进行发布的时候并没有调用hessian提供的ServiceContext.begin(...),而在hessian自带的servlet里是调用了该方法以及end方法,故在我们的逻辑里可以使用ServiceContext的getContextRequest()方法获取Request进而获取session,无奈。。。。
关于session的情况你遇到过吗? 打了一大堆字,点错了之后,全部被清掉了~郁闷 你可以参考 http://qieqie./blog/82492 上面那个帖子有点年代了,部分内容在现在好像已经不需要了。 用session无非就是想要有状态,我们可以通过添加请求头来做类似的事情,可能要结合filter来做状态的保存: 在 Hessian 4.0+中,HessianProxy 有个方法 protected void addRequestHeaders(HessianConnection conn),我们可以在每次请求之前,调用这个,然后添加请求头HessianConnection#public void addHeader(String key, String value); 在server那边读取请求头,进行标示就好了~
lvff1314 写道
跟你遇到基本相同的情况,移动多平台访问,最初决定使用PHPRPC,后来发现没有Objective-c,而所谓的hprose又不提供下载,故转道hessian,目前我用的最新的4.0.7,server端同样使用的spring进行hessian服务发布,但是遇到了一个比较尴尬的问题,我发现hessian在server端获取session比较困难,仔细查看client源码发现没有cookie机制,后对源码进行扩展增加了对response的header “Set-Cookie”的处理,但仍无效果。。。而且发现,spring通过自己的mvc进行发布的时候并没有调用hessian提供的ServiceContext.begin(...),而在hessian自带的servlet里是调用了该方法以及end方法,故在我们的逻辑里可以使用ServiceContext的getContextRequest()方法获取Request进而获取session,无奈。。。。
关于session的情况你遇到过吗? 打了一大堆字,点错了之后,全部被清掉了~郁闷 你可以参考 http://qieqie./blog/82492
跟你遇到基本相同的情况,移动多平台访问,最初决定使用PHPRPC,后来发现没有Objective-c,而所谓的hprose又不提供下载,故转道hessian,目前我用的最新的4.0.7,server端同样使用的spring进行hessian服务发布,但是遇到了一个比较尴尬的问题,我发现hessian在server端获取session比较困难,仔细查看client源码发现没有cookie机制,后对源码进行扩展增加了对response的header “Set-Cookie”的处理,但仍无效果。。。而且发现,spring通过自己的mvc进行发布的时候并没有调用hessian提供的ServiceContext.begin(...),而在hessian自带的servlet里是调用了该方法以及end方法,故在我们的逻辑里可以使用ServiceContext的getContextRequest()方法获取Request进而获取session,无奈。。。。
关于session的情况你遇到过吗?
|