几乎每个系统都要与第三方进行交互。一般来说第三方API都会提供json或xml供系统使用。
我们的目标是把api集成到系统中,并降低api对系统的影响。但是随着编码的进行,有太多的坏味道散落到系统中,比如Copy的代码满天飞;配置信息分散各处;无法有效地组织API。
面对这些问题,系统应该主动地把api封装起来,形成独立的模块供上层系统调用。
该模块涉及到的模式为[Template Method+Callack],[Factory],涉及到的元素如下
1、client:Template Method的实现者;定义了与第三方交互的过程;从Callback获取数据组装成适合第三方的信息。
2、callback:每一个api,都要实现callback,它提供方法名,参数,Url等数据给client使用
3、config:各种配置信息,如appkey,加密参数等等
4、factory:对象工厂。比如每调用第三方,系统给需要生成交易码,就可以把生成的任务委托给factory
5、model:参数的封装类,利用model,可以生成json数据,也可以生成xml数据给client使用;同时也可以根据业务参数,利用factory生成各种model
以上就是模块中的各个元素。
他们之间的调用情况如下:
1、client 依靠 callback 与 第三方交互
2、callback 结合 model 创建一个完整的apiCallback
3、factory从config获取信息并结合业务要求,创建model
一个的调用过程如下:
Model model = ModelFactory.getXXXModel(xx,bb,cc) ApiCallback back = new ApiCallback(model); Client.doClient(back);
这样的设计方式解决那些问题,如何解决.
Q1.第三方提供新的API
A1.增加一个新的Model,实现一个ApiCallback,调用doClient方法
Q2.第三方系统getName函数名称变动为getUserName
A2.进入getName对应的GetNameCallback,修改方法名
Q3.加密密钥放生变化
Q4.找到对应Config,修改密钥
给一个demo,让大家参考一下,案例已经过缩减,不足之处,多多包涵
public interface JsonCallback { public String getMethodName(); public String getUrl(); public JsonRequest getJsonRequest(); public Object onResultReceived(AccountSmsResult result); }
public class JsonClient { public static final int CONN_SERVICETOKEN_TIMEOUT = 20000; private static final Logger logger = LoggerFactory.getLogger(JsonClientHelper.class); private static final Gson gson = new Gson(); /** * 方法表述: 与远服务器进行交互,未授权 */ public static Object doUnsafeClient(JsonCallback callback) throws CException { HttpClient httpClient = new HttpClient(); // 创建Post方法 PostMethod method = createUnSafePostMethod(callback); // 配置参数 configParams(httpClient); return executeMethod(httpClient, method, callback); } /** * 方法表述:创建未授权的Post方法 */ private static PostMethod createUnSafePostMethod(JsonCallback callback) { String url = callback.getUrl() + callback.getMethodName(); PostMethod method = new PostMethod(url); method.addRequestHeader("Content-Type", "application/json"); method.setRequestEntity(wrapToRequestEntity(callback)); return method; } /** * 方法表述:配置参数 */ private static void configParams(HttpClient httpClient) { HttpConnectionManagerParams conParams = httpClient.getHttpConnectionManager().getParams(); conParams.setConnectionTimeout(CONN_SERVICETOKEN_TIMEOUT); conParams.setSoTimeout(CONN_SERVICETOKEN_TIMEOUT); } /** * 方法表述: 执行Post方法 */ private static Object executeMethod(HttpClient httpClient, PostMethod method, JsonCallback callback) throws CException { Object resultObject = null; try { int result = httpClient.executeMethod(method); if (result == HttpStatus.SC_OK) { String response = method.getResponseBodyAsString(); if (!StringUtil.isNullString(response)) { resultObject = doResponseReceived(response, callback); } } } catch (Exception e){ logger.debug(e); } finally { if (method != null) method.releaseConnection(); } return resultObject; } /** * 把Json请求对象转化为字符串,并封装到RequestEntity */ protected static RequestEntity wrapToRequestEntity(JsonCallback callback) { String req = gson.toJson(callback.getJsonRequest(), JsonRequest.class); if (logger.isDebugEnabled()) logger.debug(callback.getMethodName() + " req:" + req); try { return new StringRequestEntity(req, null, "utf8"); } catch (UnsupportedEncodingException e) { logger.error("create StringRequestEntity failed for UnsupportedEncodingException."); throw new RuntimeException("create StringRequestEntity failed for UnsupportedEncodingException."); } } /** * 方法表述:当收到服务器传递过来的信息时,如何处理 */ public static Object doResponseReceived(String response, JsonCallback callback) throws CException { AccountSmsReturn rsp = gson.fromJson(response, AccountSmsReturn.class); if (rsp != null && rsp.result != null && rsp.result.resultCode.equals("0")) { return callback.onResultReceived(rsp.result); } else { throw rsp.result.CException; } }