使用Xfire和Xstream联合构建融合自身业务系统webservice服务的java开发方案

一、Xfire部署构建
  使用Xfire来构建一套java的webservice服务接口是很容易的。现在xfire已经停止开发,被apache合并为CXF项目。我们下载Xfire项目使用jar包,扔进到项目的buildpath中去。核心的jar包括如下:
 
 
我们在src目录下新建一个文件夹META-INF,再建它的一个字文件夹xfire,里面建立文件services.xml。之后的结构如下:
 

 
我们直接看一下servics.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xfire.codehaus.org/config/1.0">
     <service>
          <!-- webserviceq名称,调用时需要指定这个 -->
          <name>readerService</name>
          <!-- 这个一般是自己公司的网址,意义不大 -->
          <namespace>http://test/HelloService</namespace>
          <!-- 接口类 -->
          <serviceClass>com.xfire.servlet.IReaderService</serviceClass>
          <!-- 实现类 -->
          <implementationClass>com.xfire.servlet.ReaderService</implementationClass>
     </service>
</beans>
 
很多人以为这样就行了,不,还没行,你指定了这个,那别人怎么访问呢。怎么把相应的请求转发到xfire那里,让它进行处理呢。这里又需要修改web.xml了。
修改后如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
     id="WebApp_ID" version="3.0">
     <servlet>
          <servlet-name>XFireServlet</servlet-name>
          <servlet-class>org.codehaus.xfire.transport.http.XFireConfigurableServlet</servlet-class>
     </servlet>

     <servlet-mapping>
          <servlet-name>XFireServlet</servlet-name>
          <url-pattern>/services/*</url-pattern>
     </servlet-mapping>
</web-app>
 
其实也就是添加了一个servlet和对应的mapping。接下来,我们在浏览器上直接输入:
 
二、使用Xstream进行java对象和XML格式的转化
  我经历的项目使用webservice一般是和第三方厂商进行数据交互,所以制定系统对接时采取XML为基础的接口操作规范文档是很重要的。不管是我们发布webservice服务接口还是作为客户端调用别人的webservice接口,和自身原有系统整合时都难免需要将XML和POJO对象进行互相转化而便于开发。这时候我们可以使用XML解析器对XML进行解析后重新创建java对象,反之亦然。但这样做代码并不经济,我们需要对XML进行历遍和检索才能转成合格的java对象。所以,Xstream帮我们完成了这样重复的工作,我们只需要正确使用它,就可以很容易将两者相互转化。
 
  Xstream是一种OXMapping 技术,是用来处理XML文件序列化的框架,在将JavaBean序列化,或将XML文件反序列化的时候,不需要其它辅助类和映射文件,使得XML序列化不再繁索。Xstream也可以将JavaBean序列化成Json或反序列化,使用非常方便。
 
  不需要在配置文件中进行额外配置,只需要往工程中导入jar包即可,我所使用的jar包为:
 
 Xstream提供了很多功能接口来自定义转化的需求。我们重点对下面几个接口的功能做一下介绍:
首先我们代码实例都使用这样的javabean来进行讲解:
package test.xstream.test;
public class Author {
    private String name;
    public Author(String name) {
            this.name = name;
    }
    public String getName() {
            return name;
    }
}
 
1、xStream.alias(String, Class),作用:将序列化中的类全量名称,用别名替换。如果不显示调用该接口,XML的tag会使用该javabean的类全量路径。
 
不使用别名alias时序列化出来的xml:
<test.xstream.test.Author>
  <name>name</name>
</test.xstream.test.Author>
 
使用别名alias时序列化出来的xml:
<Author>
  <name>name</name>
</Author>
使用方法:xstream.alias("Author",Author.class)
 
2、xstream.aliasField(String, Class, String),作用:使用别名替代属性名。
不使用别名aliasField时序列化出来的xml:
<Author>
  <name>name</name>
</Author>
 
使用别名aliasField时序列化出来的xml:
<Author>
  <author>name</author>
</Author>
使用方法:xstream.aliasFiel("author", Author.class, "name"),其实就是将类中的属性“name”指定别名“author”输入或输出。
 
3、xstream.registerLocalConverter(Class definedIn, String fieldName, Converter converter),作用:自定义转换器,可以将指定的class的属性(该属性一般是List类型)转入到特定的转换器中进行处理。
代码说明:
xstream.registerLocalConverter( AppBsChangeResult.class, "entityIDs", new ListConverter("accID"))
 
public class AppBsChangeResult extends AppBsBaseDriverResult {    
    private static Logger logger = Logger.getLogger(AppBsChangeResult.class);
private List<String> entityIDs = null;
public List<String> getEntityIDs() {
return entityIDs;
}
public void setEntityIDs(List<String> entityIDs) {
this.entityIDs = entityIDs;
}
}
 
public class ListConverter implements Converter {    
    public ListConverter(String tagName){
        this.tagName = tagName;
    }    
    private String tagName = null;    
    public String getTagName() {
        return tagName;
    }
    public void setTagName(String tagName) {
        this.tagName = tagName;
    }
    public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext arg2) {
        List<String> list = (List<String>) value;
        for (String subval : list) {
           // 为了转换成XML时,保证有<expands></expands>全标签,将值为空时不写标签只输出“”
            if("".equals(subval) && list.size()==1){
                writer.setValue(subval);
            }else{
                writer.startNode(tagName);
                writer.setValue(subval);
                writer.endNode();
            }
        } 
    }
 
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
        List<String> list = new ArrayList<String>();
        while (reader.hasMoreChildren()) {
            reader.moveDown();
            String key = reader.getNodeName();
            String value = null;
            if (reader.hasMoreChildren()) {
                value = (String)unmarshal(reader, context);
            } else {
                value = reader.getValue();
            }
                // insert into list
            list.add(value);
            reader.moveUp();
        }
        return list;
    }
 
    //覆写父类的方法,指明哪种java类型可以被转化器处理
    public boolean canConvert(Class type) {
        return type.equals(ArrayList.class); 
    }
}
 
执行xstream.registerLocalConverter( AppBsChangeResult.class, "entityIDs", new ListConverter("accID"))后,就可以将XML中N个accID标签的值转化为AppBsChangeResult类中属性"entityIDs",因为属性"entityIDs"是一个List<String>,所以就可以将N个accID的值都add进去这个List了。注意转化器的抽象接口marshal一般用在javabean对象转为XML的过程中(序列化),而抽象接口unmarshal用在XML转javabean对象的过程中(反序列化)。
 
4、xstream.addDefaultImplementation(Class, Class),作用:使用抽象类, 或父子类的转换
如果将抽象类或父类做为类的属性时, 将对象转化成xml时, 会在抽象属性对应的结点增class属性, 值为子类的包路径,
将class属性去掉办法:
xStream.addDefaultImplementation(Sun.class,Parent.class)
 
如果将抽象类或父类做为类的属性, 将xml串转化为对象时, 如果对应的结点带有class属性, 转化没有问题, 如果将xml串中的class属性去掉, 转换对象时, 就会抛异常:java.lang.InstantiationError
解决办法同样是:
xStream.addDefaultImplementation(Sun.class,Parent.class)
 
5、xstream.omitField(Class, String),作用: 定义某一个属性的值不进行xml序列化,即是对指定的字段不予处理。序列化时隐藏该字段,反序列化时该字段为null
 
6、xstream.useAttributeFor(Class, String),xstream.useAttributeFor(String, Class)和xstream.useAttributeFor(Class)
  1. xstream.useAttributeFor(String.class);                    对所有String类型的字段定义为属性tag显示
  2. xstream.useAttributeFor("name", String.class);       对所有String类型的字段名成为name 定义为属性tag显示
  3. xstream.useAttributeFor(Person.class, "name");      把字段节点设置成属性,单独使用以上方法
 <test.Person>
  <name>张三</name>
  <age>19</age>
  <string>李四</string>
  <string>王五</string>
  <string>赵六</string>
</test.Person>
将以下面XML格式输出:
<test.Person name="张三">
  <age>19</age>
  <string>李四</string>
  <string>王五</string>
  <string>赵六</string>
</test.Person>
7、xstream.addImplicitCollection(Class, String),作用:省略集合根节点
public class Person {
private String name;
private int age;
private List friends;
 
public Person(String name, int age, String... friends) {
this.name = name;
this.age = age;
this.friends = Arrays.asList(friends);
}
}
 
public class XstreamTest {
public static void main(String[] args) {
Person bean = new Person("张三", 19, "李四", "王五", "赵六");
XStream xStream = new XStream(new DomDriver());
xStream.addImplicitCollection(Person.class, "friends");
//序列化
String xml = xStream.toXML(bean);
System.out.println(xml);
//反序列化
bean=(Person)xStream.fromXML(xml);
System.out.println(bean);
}
}
xStream.addImplicitCollection(Person.class, "friends")使用前后XML对照如下。
使用前:
<test.Person>
  <name>张三</name>
  <age>19</age>
  <friends class="java.util.Arrays$ArrayList">
    <a class="string-array">
      <string>李四</string>
      <string>王五</string>
      <string>赵六</string>
    </a>
  </friends>
</test.Person>
使用后:
<test.Person>
  <name>张三</name>
  <age>19</age>
  <a class="string-array">
    <string>李四</string>
    <string>王五</string>
    <string>赵六</string>
  </a>
</test.Person>
 

 

猜你喜欢

转载自hujin.iteye.com/blog/2189345