如果您想了解cglib与xstream结合构造webservice的xml格式的入参返参的动态生成的相关知识,那么本文是一篇不可错过的文章,我们将对cglibinvokesuper进行全面详尽的解释,
如果您想了解cglib与xstream结合构造webservice的xml格式的入参返参的动态生成的相关知识,那么本文是一篇不可错过的文章,我们将对cglib invokesuper进行全面详尽的解释,并且为您提供关于2.Silverlight动态加载外部XML指定地址的WebService-(动态加载外部XML文件中指定的WebService地址)、Axis2 WebService输出自定义XML格式、axis2实现webservice之使用services.xml文件发布WebService、c# webservices 自定义返回xml格式的有价值的信息。
本文目录一览:- cglib与xstream结合构造webservice的xml格式的入参返参的动态生成(cglib invokesuper)
- 2.Silverlight动态加载外部XML指定地址的WebService-(动态加载外部XML文件中指定的WebService地址)
- Axis2 WebService输出自定义XML格式
- axis2实现webservice之使用services.xml文件发布WebService
- c# webservices 自定义返回xml格式
cglib与xstream结合构造webservice的xml格式的入参返参的动态生成(cglib invokesuper)
cglib与xstream结合构造webservice的xml格式的入参返参的动态生成
在做项目的时候遇到这样一个问题,需要与另一个系统进行Webservice通信,通信的入参、返参均是XML格式的,如下:
<PARAM>
<DET_FLAG>1</DET_FLAG>
<IO_TASK_NO>4413051710269522</IO_TASK_NO>
</PARAM>
但是这样的接口很多,而且大部分都是简单的几个属性,所以不想为每一种入参和返参都新建一个POJO类,于是就想到用Cglib动态生成类,然后再利用Xstream进行转换。
首先从网上摘了一段代码,如下:
package com.nari.component.xmlconvertor;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import net.sf.cglib.beans.BeanGenerator;
import net.sf.cglib.beans.BeanMap;
public class CglibBean {
public Object object = null;
public BeanMap beanMap = null;
public CglibBean() {
super();
}
public CglibBean(Map<String,?> propertyMap) throws Exception {
this.object = generateBean(propertyMap);
this.beanMap = BeanMap.create(this.object);
}
public void setValue(String property, Object value) {
beanMap.put(property, value);
}
public Object getValue(String property) {
return beanMap.get(property);
}
public Object getObject() {
return this.object;
}
private Object generateBean(Map<String,?> propertyMap) throws Exception {
BeanGenerator generator = new BeanGenerator();
Set<String> keySet = propertyMap.keySet();
for (Iterator<String> i = keySet.iterator(); i.hasNext();) {
String key = i.next();
//修改为获取属性的Class类型 提高兼容性
generator.addProperty(key, propertyMap.get(key).getClass());
}
return generator.create();
}
}
这段代码就是生成了一个BeanGenerator,没什么好看的,网上一堆一堆的解释,不过将generator.addProperty的参数修改为了propertyMap.get(key).getClass()),以适应自己的需求,而且需要注意的问题是如果是web运行环境,一定要排查下依赖的jar包是否有冲突。
然后,就是写自己的转换类了,先看下面的代码,这个是将给定的Map转换为XML格式的String
package com.nari.component.xmlconvertor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import com.thoughtworks.xstream.XStream;
public class XMLConvertor {
public static String convertor(Map<String,?> map,String type) throws Exception {
//实例化CglibBean
CglibBean bean = new CglibBean(map);
//为字段赋值,如果不赋值则xml中就没有这个字段
for(String mapkey : map.keySet()){
bean.setValue(mapkey, map.get(mapkey));
System.out.println(mapkey + " = " + map.get(mapkey));
}
//定制xml格式
Object object = bean.getObject();
Class<?> clazz = object.getClass();
Field[] fields = clazz.getDeclaredFields();
XStream x = new XStream();
//修改头为PARAM
x.alias(type, object.getClass());
//alias属性为对应的属性名
for (int i = 0; i < fields.length; i++) {
x.aliasField(fields[i].getName().substring(12,fields[i].getName().length()), object.getClass(), fields[i].getName());
}
//返回转换好的xml文件
String xml = x.toXML(object);
//不知对方接受的xml文件是否要去除空格,如果需要则可使用下面注释掉的方法
//xstream有bug,当参数中含有下划线的时候会转换为双下划线,这里做简单处理
return xml.replaceAll("__", "_");
}
}
注释都在类里面,需要注意的是一些xstream的alian的问题,仔细看下,没啥东西。
其次,是将给定的XML格式字符串转换为自己需要的MAP,代码如下:
package com.nari.component.xmlconvertor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
public class StringConvertor {
public static Map<String,String> convertor(Map<String,String> map,String xml,String type) throws Exception {
CglibBean bean = new CglibBean(map);
Object obj = bean.getObject();
Class<?> clazz = obj.getClass();
XStream xs = new XStream (new DomDriver());
xs.alias(type, clazz);
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
xs.aliasField(fields[i].getName().substring(12,fields[i].getName().length()), clazz, fields[i].getName());
}
Object obj2 = (Object)xs.fromXML(xml);
Class<?> clazz2 = obj2.getClass();
Method[] m3 = clazz2.getDeclaredMethods();
for(Method method :m3){
if(method.getName().indexOf("get")>-1){
String methodName = method.getName();
System.out.println(methodName);
String value = (String)method.invoke(obj2, new Object[0]);
String key = methodName.substring(3,methodName.length());
map.put(key, value);
}
}
return map;
}
}
其实就是一个动态类的转换,注意字段的对应关系就行了。
最后 ,是一个测试类,这里有一些xfire客户端的东西,可以删掉
package com.nari.webservice.client;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import com.nari.component.xfireclient.XFireClient;
import com.nari.component.xmlconvertor.StringConvertor;
import com.nari.component.xmlconvertor.XMLConvertor;
public class TestClient {
public static void main(String args[]) throws Exception{
String IO_TASK_NO = "4413051710269522";
String DET_FLAG = "1";
Object[] params = new Object[]{IO_TASK_NO,DET_FLAG};
Map<String,String> m = new HashMap<String,String>();
m.put("IO_TASK_NO", "4413051710269522");
m.put("DET_FLAG", "1");
String s = "";
try {
s = XMLConvertor.convertor(m, "PARAM");
System.out.println(s);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Map<String,String> ma1 = new HashMap<String,String>();
ma1.put("IO_TASK_NO", "");
ma1.put("DET_FLAG", "");
ma1 = StringConvertor.convertor(ma1, s, "PARAM");
System.out.println(ma1.get("IO_TASK_NO"));
System.out.println(ma1.get("DET_FLAG"));
XFireClient client = new XFireClient();
Object[] backXml = client.callService("setInputTask", params);
String backString = (String)backXml[0];
}
}
其实,这里的入参和返参都是最基本的XML格式,没有内部属性,没有内部集合,用上面两个工具类足够了,下面的这个测试类提供了对复杂XML格式的动态转换,仅仅作为一个demo,代码如下: package com.nari.component.xmlconvertor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.thoughtworks.xstream.XStream;
public class TestXStream {
public static void main(String args[]) throws Exception{
//collection demo
List<Object> list = new ArrayList<Object>();
//不知道什么原因,这里new的虚拟类设置不进去值,可以用下面反射的方法想办法按照一定的规则去赋值,这个是特殊用法,一般不用,这里做兼容性支持
//原因已经找到,是因为在MAP中使用了关键字,这点估计后台截取的时候会导致类似问题,尽量避免关键字,否则可能需要反射调用,开销很大!!
for(int iii = 0;iii<2; iii++){
Map<String,String> map01 = new HashMap<String,String>();
map01.put("ASD1", "asd1");
map01.put("CWE", "asd2");
map01.put("ASD3", "asd3");
CglibBean innerBean11 = new CglibBean(map01);
for(String mapkey : map01.keySet()){
innerBean11.setValue(mapkey, map01.get(mapkey));
}
Map<String,String> dymaMap = new HashMap<String,String>();
dymaMap.put("XXXX", "AAS");
dymaMap.put("WWWW", "ASD");
dymaMap.put("WEWEW", "dsa");
CglibBean dymaBean = new CglibBean(dymaMap);
for(String mapkey : dymaMap.keySet()){
dymaBean.setValue(mapkey, dymaMap.get(mapkey));
}
list.add(innerBean11.getObject());
list.add(dymaBean.getObject());
Object objo = dymaBean.getObject();
Class<?> clazz = objo.getClass();
Field[] testfield = clazz.getDeclaredFields();
Method[] m = clazz.getDeclaredMethods();
for(Method method :m){
if(method.getName().indexOf("get")>-1){
String s = (String)method.invoke(objo, new Object[0]);
System.out.println("从虚拟类中中取出的值为 : " + s);
}
}
}
//内部属性demo
Map<String,String> map0 = new HashMap<String,String>();
map0.put("ASD1", "asd1");
map0.put("ASD2", "asd2");
map0.put("ASD3", "asd3");
CglibBean innerBean1 = new CglibBean(map0);
for(String mapkey : map0.keySet()){
innerBean1.setValue(mapkey, map0.get(mapkey));
}
Object innerBean1Obj = innerBean1.getObject();
Class<?> clazz3 = innerBean1Obj.getClass();
Method[] m3 = clazz3.getDeclaredMethods();
for(Method method :m3){
if(method.getName().indexOf("get")>-1){
String s = (String)method.invoke(innerBean1Obj, new Object[0]);
System.out.println("22222从虚拟类中中取出的值为 : " + s);
}
}
//原始
Map<String,Object> map = new HashMap<String,Object>();
map.put("TEST1", "testValue1");
map.put("TEST2", "testValue2");
map.put("TEST3", innerBean1.getObject());
map.put("TEST4", list);
CglibBean bean = new CglibBean(map);
for(String mapkey : map.keySet()){
bean.setValue(mapkey, map.get(mapkey));
}
Object object = bean.getObject();
XStream xstream = new XStream();
Class<?> clazz = object.getClass();
Field[] fields = clazz.getDeclaredFields();
//别名
xstream.alias("ROOT", clazz);
for (int i = 0; i < fields.length; i++) {
//简化的别名
String aliasName = fields[i].getName().substring(12,fields[i].getName().length());
xstream.aliasField(aliasName, object.getClass(), fields[i].getName());
//如果不是String类型的则表明是Object的具体对象
//如果是List
if(bean.getValue(aliasName) instanceof ArrayList){
xstream.addImplicitCollection(clazz, fields[i].getName());
ArrayList arraylist = (ArrayList)bean.getValue(aliasName);
for(Object objectBean : arraylist){
Class<?> clazzList = objectBean.getClass();
Field[] fieldsList = clazzList.getDeclaredFields();
xstream.alias(aliasName, clazzList);
Method[] methods = clazzList.getDeclaredMethods();
for(Method m : methods){
if(m.getName().indexOf("set")>-1){
// m.invoke(objectBean, new Object[]{"tt!!!"});
}
}
for (int j = 0; j < fieldsList.length; j++) {
// String s = fieldsList[j].getName() ;
String aliasNameInner1 = fieldsList[j].getName().substring(12,fieldsList[j].getName().length());
xstream.aliasField(aliasNameInner1, clazzList, fieldsList[j].getName());
xstream.useAttributeFor(clazzList,fieldsList[j].getName());
}
}
System.out.println(aliasName + " 是List");
}
//如果是String
else if(bean.getValue(aliasName) instanceof String){
System.out.println(aliasName + " 是String");
}
//如果是内部类
else {
System.out.println(aliasName + " 是单独的类");
Class<?> clazzInner = bean.getValue(aliasName).getClass();
Field[] fieldsInner = clazzInner.getDeclaredFields();
for (int ii = 0; ii < fieldsInner.length; ii++) {
String aliasNameInner = fieldsInner[ii].getName().substring(12,fieldsInner[ii].getName().length());
xstream.aliasField(aliasNameInner, clazzInner, fieldsInner[ii].getName());
xstream.useAttributeFor(clazzInner,fieldsInner[ii].getName());
}
}
xstream.useAttributeFor(object.getClass(),fields[i].getName());
}
System.out.println(xstream.toXML(object));
}
}
引入上面相关类后可以直接运行,运行结果如下:
<ROOT TEST1="testValue1" TEST2="testValue2">
<TEST3 ASD2="asd2" ASD3="asd3" ASD1="asd1"/>
<TEST4 ASD3="asd3" ASD1="asd1" CWE="asd2"/>
<TEST4 WEWEW="dsa" WWWW="ASD" XXXX="AAS"/>
<TEST4 ASD3="asd3" ASD1="asd1" CWE="asd2"/>
<TEST4 WEWEW="dsa" WWWW="ASD" XXXX="AAS"/>
</ROOT>
对于复杂XML转换为动态对象的工具类暂时没有写,以后补上
2.Silverlight动态加载外部XML指定地址的WebService-(动态加载外部XML文件中指定的WebService地址)
接上节所讲的,Silverlight可以加载外部的XML文件里面的内容,那么我们可不可以在外部XML里面配置一个WebService地址,并且以 此加载这个地址来动态加载WebService呢?这样子就可以避免当WebService地址改变的时候,还要打开XAP包来重新修改 WebService配置的地址了。
答案当然是可以的。在这里,我制作了一个实例。
在前面一节里面,我们讲到了使用WebClient来下载Silverlight程序外部的XML文件内容。在本节中,我们重点需要讲解一下如何使用反射来动态生成WebService代理类。关键代码如下:
- public void InitializeServices(string serviceAddress)
- {
- BasicHttpBinding basicBinding = new BasicHttpBinding();//创建BasicHttpBinding绑定类
- basicBinding.MaxBufferSize = 2147483647;//设置最大缓存字节
- basicBinding.MaxReceivedMessageSize = 2147483647;//设置最大的接受消息缓存字节
- CustomBinding binding = new CustomBinding(basicBinding);
- BindingElement binaryElement = new BinaryMessageEncodingBindingElement();
- EndpointAddress endPoint = new EndpointAddress(serviceAddress);//根据读取的外部XML指定的Webservice地址来实例化终结点地址。
- WebServiceSoapClient _LBControl = new WebServiceSoapClient();//实例化WebService代理类
- _LBControl = (WebServiceSoapClient)Activator.CreateInstance(typeof(WebServiceSoapClient), binding, endPoint);//使用反射来实例化我们需要指定的webService地址
当然以上只是关键性代码,我们在实践中还需要自己写一个WebService做测试,在本实例源代码程序中,我们在SLreadxml.Web项目中新建了一个WebService.asmx页面,此页面写了一个简单的WebService方法:
- [WebMethod]
- public string HelloWorld()
- {
- return "Hello World For TestData";
- }
然后我们右键点击SLreadxml项目名然后选择“添加服务引用”,在弹出的窗口中,我填入SLreadxml.Web中 WebService.asmx页面的http地址。(注意这里的Http以你自己的WebService地址为准,你可以重新架设一个网站目录或者IP 上。)http://localhost:1239/webService.asmx,然后点击“前进”,在这里创建好这个服务引用的代理类。并且命名此命名空间名为LBControl,然后我们需要在App.xaml.cs文件中引入以下命名空间:
- using System.IO;
- using System.Xml;
- using System.Windows.browser;
- using System.ServiceModel;
- using System.ServiceModel.Channels;
- using SLreadxml.LBControl;
当然System.ServiceModel域名空间还需要单独引用其DLL文件。在SLreadxml右键--“添加引用”。
另外想要WebService能够被访问到,还需要添加clientaccesspolicy.xml文件,此文件叙述了你可以安全的引用某一个网 站下的WebService.类似于安全许可吧。值得注意的是这个文件必须放在你的网站的根目录下面,那么你的这个WebService文件才能够被访问 到。不是虚拟目录的根目录,而是你网站的根目录。切记。
clientaccesspolicy.xml源代码:
- <?xml version="1.0" encoding="utf-8" ?>
- <access-policy>
- <cross-domain-access>
- <policy>
- <allow-from http-request-headers="*">
- <domain uri="*"/>
- </allow-from>
- <grant-to>
- <resource path="/" include-subpaths="true"/>
- </grant-to>
- </policy>
- </cross-domain-access>
- </access-policy>
好了。现在基本上已经可以实现动态的访问XML来动态的读取WebService地址。而不用每次都要去XAP包里面修改WebService地址了。那样太麻烦了。