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