公司接口程序,使用的是直接读取XMl, 然后使用XStream解析返回的 XML 返回生成的对象。?
?
设计中使用了动态代理的模式,
?
并且结合自定义注解来定义常量和传递的参数 。
?
动态代理 :
?
定义了接口 Feed 及相应的方法, 使用注解传递参数和常量 。
?
?
@DefaultParams(@DefaultParam(key="apikey",value=Feed.APIKEY)) @ServiceURL("https://xml.xxxxxx.com/datafeed/Feed.asmx") public interface Feed { /** 提供服务标识 */ public static final String APIKEY = "82DD63FF-A7EB-47XXXXXXXXXXXXXX"; /** 获取地区 */ @GetMethod @HotelCache(timeoutByHour=24*7) @MethodName("GetFeed") @DefaultParams(@DefaultParam(key="feed_id",value="1")) @XStreamRoot("/Region_feed/regions") @XStreamAnnotation(@XStreamAlias(key="region",value=RegionFeed.class)) public List<RegionFeed> getRegionFeed(); }?
在 Action 初始化的时候, 加载 Feed 接口的动态代理:
?
public class HotelListAction extends BaseAction { static { defaultParams = new ArrayList<Object>(); FeedDefaultParam param = new FeedDefaultParam(); param.setOlanguage_id(LEAGUAGE_CODE); defaultParams.add(param); feed = IXRProxyFactory.newProxyInstance(Feed.class,defaultParams); } public void geoCity() { CityFeedParams params = new CityFeedParams(); params.setMcountry_id(id); List<CityFeed> cities = null; try{ cities = feed.getCityFeed(params); }catch(Exception ex){ logger.error("查找城市不存在!"); } outputPlainText(JSONArray.fromObject(cities).toString()); } }?
这里使用了自定义的代理工厂,
?
/** * 代理工厂 * @version 1.0 2010-12-4 * @author ixr_(mail@ixr.name) */ public class IXRProxyFactory{ /** 获取代理对象 */ public static <T> T newProxyInstance(Class<T> interfaceClass,List<Object> defaultParams){ IXRProxy proxy = new IXRProxy(); proxy.setDefaultParams(defaultParams); proxy.setInterfaceClass(interfaceClass); Object proxyImpl = Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, proxy); return interfaceClass.cast(proxyImpl); } }?
其中 ,IXRProxy 就是代理处理逻辑类 ,其继承接口 InvocationHandler? ,实现方法:
public Object invoke(Object proxy, Method method, Object[] args)
此方法体, 会代替被代理接口的每个方法执行,并且返回? Object 对象。
?
public class IXRProxy implements InvocationHandler{ /** 默认编码 */ private static final String ENCODING = "utf-8"; /** 接口 */ private Class<?> interfaceClass = null; public void setInterfaceClass(Class<?> interfaceClass){ this.interfaceClass = interfaceClass; } /** 默认参数 */ private List<Object> defaultParams = new ArrayList<Object>(); public void setDefaultParams(List<Object> defaultParams){ this.defaultParams = defaultParams; } private Object invoke(Object proxy, HttpClientParam httpClientParam, Method method, Object[] args) throws Throwable { String xml = null; try { if(httpClientParam.isGet){ xml = HttpClientUtils.getHTML(httpClientParam.url, httpClientParam.params); }else{ xml = HttpClientUtils.postHTML(httpClientParam.url, httpClientParam.params); } XStreamAnnotation xStreamAnnotation = method.getAnnotation(XStreamAnnotation.class); if (xStreamAnnotation != null) { XStreamAlias[] xStreamAliasArray = xStreamAnnotation.value(); for (XStreamAlias xStreamAlias : xStreamAliasArray) { xStream.alias(xStreamAlias.key(), xStreamAlias.value()); String[] useAttributes = xStreamAlias.useAttributes(); for (String useAttribute : useAttributes) { xStream.useAttributeFor(xStreamAlias.value(), useAttribute); } } } Document dom = DocumentHelper.parseText(xml); return xStream.fromXML(xml); } else { return null; } } catch (Exception e) { log.error("取接口数据时出错", e); return null; } }?
?
代理方法中, 根据接口定义的注解参数, 转换返回的 XML 所对应的类型, 并且返回。
?
自定义注解 :
?
自定义的注解接口 :
?
public interface IXRProxyAnnotation { /** 服务地址 */ @Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ServiceURL{ String value(); } /** XStream解析类型 */ @Documented @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface XStreamAnnotation{ XStreamAlias[] value(); AttributeValueConveter[] attributeValueConveters() default {}; } /** XStream解析根目录 */ @Documented @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface XStreamRoot{ String value(); } /** XStream解析类型映射 */ @Documented @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface XStreamAlias{ String key(); Class<?> value(); String[] useAttributes() default {}; } }?
注解中, 可定义
??????? String key();
??????? Class<?> value();
??????? String[] useAttributes() default {};
等等参数, 标注注解的时候, 需要提供这些默认值 。。
?
@XStreamAlias(key="country",value=CountryFeed.class)?
在 invoke 方法中, 通过接口类对象的方法:
//获取接口参数
??????? String serviceURL = interfaceClass.getAnnotation(ServiceURL.class).value();
?
通过参数: Method method 得到方法标记的参数
//方法标记参数
??????? DefaultParams defaultParamsAnnotation = method.getAnnotation(DefaultParams.class);
??????? if(defaultParamsAnnotation != null){
??????????? for (DefaultParam defaultParam : defaultParamsAnnotation.value()) {
?????????? ??? ?params.put(defaultParam.key(), defaultParam.value());
??????????? }
??????? }
?
获得传入的参数:
?
//获取传入参数 for (Object param : (args == null ? new Object[0] : args)) { argsList.add(param); } //转换请求参数列表 for (Object param : argsList) { Field[] fiedl = param.getClass().getDeclaredFields(); for (Field field : fiedl) { Param paramAnnotation = field.getAnnotation(Param.class); if (paramAnnotation != null) { field.setAccessible(true); params.put(paramAnnotation.value().isEmpty() ? field.getName() : paramAnnotation.value(), String.valueOf(field.get(param))); } } }?
比如,在获取城市数据的时候, 传入参数定义的类 :
?
public class CityFeedParams { @Param private Integer mcountry_id; //--国家ID public Integer getMcountry_id() { return mcountry_id; } public void setMcountry_id(Integer mcountry_id) { this.mcountry_id = mcountry_id; } }
?
必须要在变量前面加自定义注解: @Param
?
才能在invoke方法中,使用 Param paramAnnotation = field.getAnnotation(Param.class); 得到值,传出到Webservice...
?
?
?
