HTTP+XML接口客戶端 結合策略模式實現總結


  在項目中,我們經常會使用到http+xml的接口,而且不僅僅的是一個,可能會有多個http的接口需要實時的交互.但是http接口的發送消息的公共部分是一樣的,只有每個接口的報文解析和返回報文是不同的,此時考慮到把變化和不變化的隔離出來,采取用策略模式,把公共的部分代碼抽取隔離出來,每個http接口的不同的處理邏輯單獨自己處理,這樣也方便了后期的修改和擴展,可以很方便的修改單獨的接口處理邏輯和添加新的http接口到項目中使用,而不用修改以前的設計.下面就http+xml接口的發送客戶端采用簡單的策略模式實現:

項目背景:SSH架構

第一,實現發送客戶端的基類,把接口需要的基本參數信息,抽取出來,封裝公共的發送方法,封裝公共的報文組合方法,以及注入不同接口消息處理的報

 * 功能詳細描述:HttpClient 發送報文基礎類
 * 
 * @author lilin
 * @since 2015-1-7
 */
@Service
public class BaseHttpClientSender {

   //注入接口的系統標示 @Value(
"${appCode}") protected String appCode;
   //注入權限id @Value(
"${authId}") protected String authId;
  //注入需要訪問服務方的地址url @Value(
"${httpUrl}") protected String url; private Logger logger = Logger.getLogger(BaseHttpClientSender.class); private IHttpSenderHandle httpSenderHandle;
public void setHttpSenderHandle(IHttpSenderHandle httpSenderHandle) { this.httpSenderHandle = httpSenderHandle; } /** * 功能描述: 發送接口 * * @return 返回結果 * @since 2014-9-17 */ public Map<String, Object> httpClentSender(final String msg) { logger.info("@@HttpClient sendXml : " + msg); HttpClient httpClient = new DefaultHttpClient(); Map<String, Object> result = new HashMap<String, Object>(); HttpPost method = new HttpPost(url); ContentProducer cp = new ContentProducer() { public void writeTo(OutputStream outstream) throws IOException { Writer writer = new OutputStreamWriter(outstream, "UTF-8"); /** * 獲取請求的xml格式數據 */ writer.write(msg); writer.flush(); } }; method.setEntity(new EntityTemplate(cp)); method.addHeader("Content-Type", "text/xml"); HttpResponse response = null; try { response = httpClient.execute(method); } catch (ClientProtocolException e) { logger.error("@@HttpClient Excute ERROR! ClientProtocolException:", e); result.put(Constants.RESFLAG, Constants.RES_E); result.put(Constants.RESMSG, "調用接口出錯!"); } catch (IOException e) { logger.error("@@HttpClient IOException!", e); result.put(Constants.RESFLAG, Constants.RES_E); result.put(Constants.RESMSG, "IO出錯!"); } if (response != null) { int status = response.getStatusLine().getStatusCode(); logger.info("@@HttpClient statusCode : " + status); if (status == HttpStatus.SC_OK) { HttpEntity resEntity = response.getEntity(); try { result = httpSenderHandle.handleResponseMsg(resEntity.getContent()); } catch (Exception e) { logger.error("@@HttpClient Get ResponseBody ERROR!", e); result.put(Constants.RESFLAG, Constants.RES_E); result.put(Constants.RESMSG, "獲取返回報文時出錯!"); } } else { logger.info("@@HttpClient HttpStatus ERROR!"); result.put(Constants.RESFLAG, Constants.RES_E); result.put(Constants.RESMSG, "接口返回失敗!"); } } logger.info("@@HttpClient SUCCESS"); return result; } /** * 功能描述: 封裝消息提醒頭部 * * @return mbfHeader * @since 2014-9-18 * @version */ protected Element getMbfHeader(String serviceCode, String opertion) { Element mbfHeader = DocumentHelper.createElement("MbfHeader"); addElementHead(mbfHeader, "ServiceCode", serviceCode); addElementHead(mbfHeader, "Operation", opertion); addElementHead(mbfHeader, "AppCode", appCode); addElementHead(mbfHeader, "UId", UUID.randomUUID().toString()); addElementHead(mbfHeader, "AuthId", authId); return mbfHeader; } /** * 在目標節點上面增加一個節點: <br> * 〈在目標節點上面增加一個節點,並返回增加的節點,節點的內容根據傳入的elementText定〉<br> * 如果傳入的文本是null,那么僅僅增加節點,不增加value * * @param targetElement * @param elementName * @param elementText * @return */ protected Element addElement(Element targetElement, String elementName, String elementText) { Element temp = targetElement.addElement(elementName); if (elementText != null) { temp.addCDATA(elementText); } return temp; } /** * 在目標節點上面增加一個節點: <br> * 〈在目標節點上面增加一個節點,並返回增加的節點,節點的內容根據傳入的elementText定〉<br> * 如果傳入的文本是null,那么僅僅增加節點,不增加value * * @param targetElement * @param elementName * @param elementText * @return */ protected Element addElementHead(Element targetElement, String elementName, String elementText) { Element temp = targetElement.addElement(elementName); if (elementText != null) { temp.addText(elementText); } return temp; } public String getAppCode() { return appCode; } public void setAppCode(String appCode) { this.appCode = appCode; } public String getAuthId() { return authId; } public void setAuthId(String authId) { this.authId = authId; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } }

第二,實現業務類需要注入的實際發送接口信息的子類<LowPriceApproveHttpSender> 繼承自基類實現,同時注入自己需要的基本參數信息,和實際的消息處理接口實現類.

/**
 * 功能詳細描述:超低價審批的接口實際發送
 * 
 * @author lilin
 * @since 2014-9-17
 */
@Service
public class LowPriceApproveHttpSender extends BaseHttpClientSender {

    private Logger logger = Logger.getLogger(LowPriceApproveHttpSender.class);

    @Value("ZYCRMExamineResults")
    private String serviceCode;
    @Value("examineResults")
    private String operation;

    @Resource
    private IHttpSenderHandle lowPriceApproveHttpSenderHandle;

    @PostConstruct
    public void injectHttpSenderHandle() {
        super.setHttpSenderHandle(lowPriceApproveHttpSenderHandle);
    }

    public Map<String, Object> sendCrm(PriceBaseInfo base, LowPriceApprove approve, List<LowPriceDetail> details,
            User user, String nextStep) {
        logger.info("LowPrice APPROVE sendCrm START");
        // 獲取報文
        String msg = getSenderMsg(base, approve, details, user, nextStep);
        // 發送
        Map<String, Object> res = super.httpClentSender(msg);
        return res;
    }

    private String getSenderMsg(PriceBaseInfo base, LowPriceApprove approve, List<LowPriceDetail> details, User user,
            String nextStep) {

        Document document = DocumentHelper.createDocument();
        document.setXMLEncoding("UTF-8");
        Element root = document.addElement("MbfService");
        Element input1 = root.addElement("input1");
        input1.add(getMbfHeader(serviceCode, operation));

        Element mbfBody = root.addElement("MbfBody");
        Element input = mbfBody.addElement("input");

        addElement(input, "applNo", base.getBusinessCode());
        addElement(input, "apprDate", base.getEndDate().split(" ")[0]);

        // 如果為超公司底價審批
        if ("cmp".equals(approve.getBranchType())) {
            String reportUnitPrice = approve.getReportUnitPrice();
            addElement(input, "apprPrice", StringUtils.isEmpty(reportUnitPrice) ? approve.getSignUnitPrice()
                    : reportUnitPrice);
            addElement(input, "apprName", StringUtils.isNotEmpty(approve.getApprovalName()) ? approve.getApprovalName()
                    : user.getUserName());
            addElement(input, "operatorNo", user.getUserId());
        } else {
            addElement(input, "apprPrice", null);
            addElement(input, "apprName", null);
            addElement(input, "operatorNo", null);
        }
        addElement(input, "apprTime", base.getEndDate().split(" ")[1]);
        addElement(input, "crmNo", approve.getOrderNo());
        addElement(input, "personId", base.getApplierNo());
        addElement(input, "projCode", approve.getProjectCode());
        addElement(input, "result", "SE".equals(nextStep) ? "1" : "2");

        if (CollectionUtils.isNotEmpty(details)) {
            Element tables = mbfBody.addElement("tables");
            for (LowPriceDetail detail : details) {
                Element tQuota = tables.addElement("tQuota");
                addElement(tQuota, "limitType", detail.getLimitType());
                addElement(tQuota, "useValue", detail.getAssignLimit());
                addElement(tQuota, "apprRemark", detail.getRemark());
            }
        }
        return document.asXML();
    }
}

第三,定義好消息處理接口類:所有的接口處理實際類 統一實現此接口,接口用於發送消息基類的注入.實際的處理類在子類中注入實現.

/**
 * 發送Http接口
 * @author lilin
 * @since 20150918
 */
public interface IHttpSenderHandle {

    /**
     * 
     * 功能描述: <br>
     * 〈功能詳細描述〉
     *
     * @param content
     * @return
     * @see [相關類/方法](可選)
     * @since [產品/模塊版本](可選)
     */
    Map<String, Object> handleResponseMsg(InputStream content);

}

第四,實現,每個接口需要實際的處理消息的類:用於消息發送子類的組合注入

/**
 * 功能詳細描述: httpClient 接口返回消息
 * 
 * @author lilin
 * @since 2014-9-17
 */
@Service
public class LowPriceApproveHttpSenderHandle implements IHttpSenderHandle {

    private Logger logger = Logger.getLogger(LowPriceApproveHttpSenderHandle.class);

    @Override
    public Map<String, Object> handleResponseMsg(InputStream inputStream) {

        Map<String, Object> result = new HashMap<String, Object>();
        SAXReader sb = new SAXReader();
        Document document;
        try {
            document = sb.read(inputStream);
        } catch (DocumentException e) {
            logger.info("ERROR IN Reader InputStream:", e);
            result.put(Constants.RESFLAG, Constants.RES_E);
            result.put(Constants.RESMSG, "返回報文轉換出錯!");
            return result;
        }
        logger.info("@@HttpClient 解析返回報文:" + document.asXML());
        Element root = document.getRootElement();
        Element outElement = root.element("output1");
        Element mbfHeader = outElement.element("MbfHeader");
        Element serviceResponse = mbfHeader.element("ServiceResponse");
        Element status = serviceResponse.element("Status");
        if ("COMPLETE".equals(status.getText())) {
            Element bodyElement = outElement.element("MbfBody");
            Element output = bodyElement.element("output");
            Element reFlag = output.element("reFlag");
            Element errorMessage = output.element("errorMessage");

            result.put(Constants.RESFLAG, reFlag.getText());
            result.put(Constants.RESMSG, errorMessage.getText());
        } else {
            logger.info("@@HttpClient 接口沒有成功返回:" + status.getText());
        }

        return result;
    }

}

到此,簡單的http+xml+策略模式的實現消息的發送客戶端就完成了,此時,只要在我們需要調用的服務類之中,注入我們的客戶端發送子類bean,就能實時的發送xml消息交互了.

后面擴展和修改也十分的方便,不需要修改已有的設計和代碼:

新增一個新的發送接口:

1,新增加發送子類,實現當前的發送基類<BaseHttpClientSender>,注入需要處理消息的方法handle類.

2,新增處理消息的handle類,實現當前的<IHttpSenderHandle>接口,

3,把新增加的子類發送類的bean,注入到需要調用發送接口的服務類中,就可以方便的實現接口信息的報文發送請求了.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM