敏捷开发的过程中,说不幸也好,说幸运也好,遇到了比较棘手的技术问题。
gxpt项目下有四个子系统:jc、pj、ks、qx。我们pj开发小组需要从jc组读取数据。面向接口编程,系统之间的交互采用webservice进行通信。对我们pj组来说,jc那边的接口一共分为两类:一是公共使用的(该接口称为jc_for_common);一是专门为pj系统使用的(该接口称为jc_for_pj)。
jc专门为pj系统使用的接口,是与业务息息相关的,所以由pj组员进行编写,然后由pc组统一发布称webservice供其他开发组使用。
通过webservice调用jc_for_common中的方法时,会出现一个非常奇怪的现象:本机jboss能够调通,发布成webservice后报错:实体中本地序列化Id与远程序列化Id不一致错误。
1、各实体中序列化统一采用“1L”作为序列化Id:“private static final long serialVersionUID = 1L;”
2、发布后的webservice的传输的wsdl完全正确;
3、经过多次测试,报这种错误的方法都有一个特点:相应实体中有继承映射实体的引用。
首先,“1L”作为序列化Id不会有问题。它是根据实体的特性(如属性、方法等),来生成一个特定的值,这一个值是固定的,所以,这里不会有问题。
所以被迫不得已得出推测:实体采用JPA的继承映射,发布成webservice之后,尽管在wsdl中有看似正确的相应的类型,但是应用端仍然无法识别该类型。
根据此推论,jc组成员迅速将jc_for_common中的涉及继承映射实体的查询方法,改用原生SQL语句进行查询(之前都是写的HQL语句)。
修改后,发布称webservice也能够正常调通,所以,应该是webservice在传输的过程中,采用有继承映射的实体写HQL语句不知哪里出了问题。
webservice的实现,原则是这样:尽一切可能保证接口的稳定性。我们采取的行动是所有开发人员坐在一起,将接口确定下来,然后将实现分下去。
jc_for_pj实现的部分业务逻辑比较复杂。而jc那边儿一直催,因为这边写完了才能一起发布webservice(当时真的天真的以为,webservice发布完了就万事大吉了,结果证明并不是每一个程序员都写单元测试的)。所以,我实现的部分仅仅写了一个大概的实现。打算先发布出来一版,以后修改实现不是那么麻烦。
后来,大概又花费了将近一个星期的时间完成实现的修改。几经艰辛,在本机jboss测试通过后,发布称webservice后,又报错:实体中本地序列化Id与远程序列化Id不一致错误。
由于业务比较复杂,我只能自己封装一个方法,然后拼接传入原生SQL语句(注意这里使用的就是原生SQL语句),但是为什么会报错呢?
1、之前的方法都是返回list,而jc_for_pj中我写的方法返回PageModel;
2、发布后的webservice的传输的wsdl完全正确;
3、返回的信息包含的东西包含很多表中内容,有些实体中有继承映射实体的引用;
4、已将各实体的序列化Id修改为具体的值,如:“private static final long serialVersionUID = -5104867321266255995L;”
5、可能会与JDK有关。
经过本人测试,使用JDK发布webservice,需要使用JDK的版本在1.70或者1.70以上。项目中使用的JDK是1.60版本。但是项目中的webservice是使用CXF发布的,而不是JDK发布的。这里只是猜测,未经实践(尝试换成1.70版本的JDK,但是本地Eclipse不支持,然后由与项目催的比较紧,就为测试……给自己懒惰找个理由吧)。
另一种可能,返回的PageModel对象类型,也可能是导致运行出错的结果之一。但是经查看wsdl发现,返回的PageModel对象类型正确无误。经查看具体的错误信息,说什么SOA解析错误。
所以,我认为采用原生SQL,同时报的SOA解析错误,所以这里不再是继承映射的问题了,而是Webservice传输过程中,出现了错误。
结果,我放弃了将jc_for_pj接口发布成webservice的想法。采用了折中的方式:在业务逻辑层,注入远程EjbBean,我写的那两个方法,采用注入EjbBean的方式实现。这里能够正常运行。
于此有想法或者有解决方案的童鞋,欢迎拍砖呀..
开发的过程中,由于这个问题是未预料到的,所以导致该小项目的完成一拖再拖。敏捷计划也一改再改。我想,在敏捷开发的过程中,遇到技术难点是在所难免的。
我们应该将技术攻坚部分与项目进度分开,将料想到的技术难点做成一个一个的小Demo。同时,每一个story不应太长,最长2天,这样才能将你每天都在做什么落实到实处。