HessianPHP使用注意事项

来源:互联网 发布:网红脸是什么体验知乎 编辑:程序博客网 时间:2024/05/16 09:12
HessianPHP_v2.0.3.zip, 在php作客户端,java作服务器端时,使用注意事项:
下载地址:http://osdn.jp/projects/sfnet_hessianphp/releases/

1.需要在php.ini中配置CURL模块:
extension=php_curl.dll

2.php传中文给java, 和java返回中文给php,都有中文乱码问题:
1)php和java文件本身都采用UTF-8编码
2)在php.ini中开启mbstring模块:
extension=php_mbstring.dll
同时配置:
mbstring.internal_encoding = UTF-8

因为:
Hessian2Writer.php文件:
    function writeStringData($string){
        return HessianUtils::writeUTF8($string);
    }

HessianUtils.php文件:
    public static function isInternalUTF8(){
        $encoding = ini_get('mbstring.internal_encoding');
        if(!$encoding)
            return false;
        return $encoding == 'UTF-8';
    }

3).response返回设置为UTF-8:
header("Content-Type: text/html; charset=UTF-8");


或者,统一改php.ini文件:
mbstring.http_output = UTF-8
;启用字符转换功能
output_handler = mb_output_handler

php文件保存为UTF-8编码方式,避免文件中的中文显示乱码


4)默认配置:
HessianFactory.php
define('HESSIAN_PHP_VERSION', '2.0');  --------->hessian 2.0协议
        $this->transports = array(
            'CURL' => 'HessianCURLTransport',  ----------->传输协议
            'curl' => 'HessianCURLTransport',
            'http' => 'HessianHttpStreamTransport'
        );

3.java返回值问题:
1).java端返回(自定义的)对象,在php端为stdClass Object, 它具有一个属性 [__type] => org.model.User

2).而对于普通对象,例如java的Date对象,在php就是DateTime对象:
[birthday] => DateTime Object ( [date] => 2012-07-27 15:27:31 [timezone_type] => 1 [timezone] => +00:00 )

3).java的List, Set, Map,在php就是Array.
List为php的序号数组:
[productList1] => Array (
     [0] => stdClass Object ( [__type] => org.model.Product [name] => 布匹 [price] => 300 )

)


Map为php的名称数组:
[productMap] => Array (
     [布匹] => stdClass Object ( [__type] => org.model.Product [name] => 布匹 [price] => 300 )
)

java的返回值,php端不需要做任何特殊映射,可以直接采用->x->y的方式去取值显示.

4).同一个对象,即放在List中,又放在Map中,返回值中为什么只显示一处有值?
这其实是HessianPHP_v2.0.3.zip的一个bug.
hessian协议中为了减少重复对象的序列化,采用了引用的方式,参见:
Hessian 2.0 序列化协议规范
http://wenku.baidu.com/view/3832199951e79b8968022641.html

经过debug调试,发现:
需要修改Hessian2Parser.php中
function untypedMap($code, $num){
//             if(HessianRef::isRef($key)) $key = &$this->objectlist->reflist[$key->index];
//             if(HessianRef::isRef($value)) $value = &$this->objectlist->reflist[$value->index];
            if(HessianRef::isRef($key)) $key = $this->refmap->objectlist[$value->index];
            if(HessianRef::isRef($value)) $value = $this->refmap->objectlist[$value->index];
}
同样下面方法也需要修改:
function typedMap($code, $num)
{
...
}

测试结果:
objectstdClass Object ( [__type] => User [name] => yangwenchao杨文超 [country] => CHINA [birthday] => DateTime Object ( [date] => 2012-07-28 09:02:32 [timezone_type] => 1 [timezone] => +00:00 ) [productList1] => Array ( [0] => stdClass Object ( [__type] => Product [name] => 布匹 [price] => 300 ) ) [productList2] => Array ( ) [productList3] => [productMap] => Array ( [布匹一] => stdClass Object ( [__type] => Product [name] => 布匹 [price] => 300 ) [布匹二] =>stdClass Object ( [__type] => Product [name] => 布匹 [price] => 300 ) ) )

4.php向java传参问题(实体类):

  1. class User{
       var $userId;
       var $userName;
    };
  2. require_once 'HessianPHP_v2.0.3/src/HessianClient.php';
    require_once 'HessianPHP_v2.0.3/src/HessianOptions.php'; 
    require_once 'HessianPHP_v2.0.3/src/HessianTypeMap.php'; 

    $testurl = 'http://127.0.0.1/Service/hessian/userInfoService';
    $handler = new HessianTypeMap();
    $handler->mapType('User', 'com.ub.common.sys.entity.User'); 
    $proxy = new HessianClient($testurl);    
    $user2=$proxy->getUserByUserId('01');
    print_r($user2);
    echo $user2->userId;
    echo $user2->getUserId();


5.关于类型映射:
php是无类型的,默认情况下远程的Object都会变成php的stdClass这样的万能对象。持有这样的对象进行访问的时候,关于对象的属性name, price等信息需要尝试指定。(工作正常)

但是如果把远程Object映射成php本地的自定义的phpObject以后,就可以用一个对象的模子class来框住对象的实体形式,而且编辑器还可以支持语法提示功能。

采用这种方式,在解析返回值时,可以得到便利,在向Java传递对象作为参数时,也可以提供一些便利。

$options = new HessianOptions();
$options->typeMap['Person'] = '*.Person';
$options->typeMap['CalendarHandler'] = 'com.caucho.hessian.io.CalendarHandle';
$options->parseFilters['@CalendarHandler'] = array('CalendarHandler','calendarToDateTime');
$options->writeFilters['@Person'] = array('CalendarHandler','writePerson');
参见例子:
AdvancedExample  Advanced type mapping and filtering
http://code.google.com/p/hessianphp/wiki/AdvancedExample

如果不采用自动映射方式,php向java传参时,只能采用php原生的stdClass来传值:
        $person = new stdClass();      
        $person->__type = 'org.model.Person'; //参照java返回值的形式,添加上__type属性,其实无效.
        $person->id = 1;
        $person->firstName = '杨';
        $person->lastName = '文超';
        //$person->birthDate = '';       
       
        $user = $proxy->getUserABC($person);

在java端,总是抛出warning, 显然,java端无视了参数$person->__type的意义:
java.lang.ClassNotFoundException: stdClass
2012-7-28 11:13:22 com.caucho.hessian.io.SerializerFactory getDeserializer
警告: Hessian/Burlap: 'stdClass' is an unknown class in WebappClassLoader
  context: /springhessian
  delegate: false
  repositories:
    /WEB-INF/classes/
----------> Parent Classloader:
org.apache.catalina.loader.StandardClassLoader@1adc30

去掉warning的解决办法:
$options->typeMap['stdClass'] = 'org.model.Person';

        $options = new HessianOptions();
        $options->typeMap['stdClass'] = 'org.model.Person';       
        $url = "http://localhost:8080/springhessian/remoting/hessianService"; 
        $proxy = new HessianClient($url, $options); 
        echo ""; 
 
        $person = new stdClass();      
        $person->__type = 'org.model.Person';
        $person->id = 1;
        $person->firstName = '杨';
        $person->lastName = '文超';
        //$person->birthDate = '';       
  
        $user = $proxy->getUserABC($person);

工作正常。

但是这种方法,只能应对一个类型参数,如果有两个类型的参数,如org.model.Person和org.model.Company,就又无法正常工作了, 因为stdClass不知道到底需要映射到哪一个Java类型上。

所以,在php向java传参时,需要在php中自定义若干个与java相对应的类型,配合
$options->typeMap['Person'] = 'org.model.Person';
来一起完成参数类型映射功能。
例如:
class Person{
        var $id;
        var $firstName;
        var $lastName;
        var $birthDate;
}
$p = new Person();
$p->firtName = 'John';
$p->lastName = 'Sheppard';
$options = new HessianOptions();
$options->typeMap['Person'] = 'com.sample.hessian.Person';
$proxy = new HessianClient($url, $options);
$result = $proxy->add($p);
print_r($result);

另外:
$options->typeMap['Person']='com.sample.hessian.Person';->精确指定,可用于解析返回值,也可用于传参
$options->typeMap['Person']='*.Person';  ------>采用通配,只适用于解析返回值,不能用于传参

6.关于类型自动映射的,回调处理:
$options->parseFilters['@CalendarHandler'] = array('CalendarHandler','calendarToDateTime');
$options->writeFilters['@Person'] = array('CalendarHandler','writePerson');

对于包装类型,有两种方式处理:一是原生构建层级关系,二是采用回调去除包装

一是原生构建层级关系:
$p = new Person();
$p->firstName = 'John';
$p->lastName = 'Sheppard';
$p->birthDate = new CalendarHandler(new DateTime('1970-06-14 12:00:00'));
... send the object

二是采用回调去除包装
$options->parseFilters['@CalendarHandler'] = array('CalendarHandler','calendarToDateTime');
$options->writeFilters['@Person'] = array('CalendarHandler','writePerson');

建议尽量不要有包装类型,如果一定有,采用“原生层级类型”比较容易理解一些。

7.原生传值:
    public User getUserList(List list);  -------->List  ------>对应于php的数字array
    public User getUserSet(Set set);  -------->Set ------>对应于php的名字array
    public User getUserMap(Map map);  -------->Map ------>对应于php的名字array

        //$parameter = array('杨', '文超'); //数字array        
        //$parameter = array('firstName'=>'杨', 'lastName'=>'文超');//名字array   
        $parameter = array('firstName'=>'杨', 'lastName'=>'文超');  //名字array        
        //$user = $proxy->getUserList($parameter);
        //$user = $proxy->getUserSet($parameter);
        $user = $proxy->getUserMap($parameter);

8.返回值为null
$user = ------->如果java端返回值为null,那么php端为
$result = isset($user); ------->结果为false
echo $result;  ------>打印后,显示不了false字样

PHP boolean to string with modification & a condition
http://stackoverflow.com/questions/3671455/php-boolean-to-string-with-modification-a-condition

echo(is_bool($x) ? ($x ? "true":"false"):$x);
Not the easiest to read but gets the job done!
0 0
原创粉丝点击