在WebService中使用动态代理模式和Annotation注解

公司接口程序,使用的是直接读取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...

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值