HttpClentDeliver 发货通用类
package net.etongbao.vasp.onpay.product;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.HTTP;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 请求客户端通用类
*
* @author Fu Wei
*
*/
public class HttpClientDeliver {
private static final Logger LOG = LoggerFactory.getLogger(HttpClientDeliver.class);
public static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
/**
* post请求
*
* @param descUrl
* @param strEntity
* @return InputStream
*/
public static InputStream clientPostDeliver(String descUrl, String strEntity) {
DefaultHttpClient httpclient = new DefaultHttpClient();
try {
// 目标地址
HttpPost httppost = new HttpPost(descUrl);
LOG.debug("执行请求{}", httppost.getRequestLine());
// 构造字符串数据
StringEntity reqEntity = new StringEntity(strEntity);
// 设置类型
reqEntity.setContentType(CONTENT_TYPE);
// 设置请求的数据
httppost.setEntity(reqEntity);
// 执行
HttpResponse rsp = httpclient.execute(httppost);
HttpEntity entity = rsp.getEntity();
return entity.getContent();
} catch (UnsupportedEncodingException e) {
LOG.error("不支持的编码错误{}", e);
httpclient.getConnectionManager().shutdown();
} catch (ClientProtocolException e) {
LOG.error("客户端协议错误{}", e);
httpclient.getConnectionManager().shutdown();
} catch (IOException e) {
LOG.error("IO错误{}", e);
httpclient.getConnectionManager().shutdown();
} finally {
// 当不再需要HttpClient的实例,关闭连接管理器,以确保立即释放所有系统资源,
//当前不关闭管理器,否则在响应的大数据量内容只获取部分。
//httpclient.getConnectionManager().shutdown();
}
return null;
}
/**
* 系统使用UTF-8编码,中文字符需要把中文字替换成UTF-8编码
*
* @param content
* @param encoding
* @return
*/
public static String encode(final String content, final String encoding) {
try {
return URLEncoder.encode(content, encoding != null ? encoding : HTTP.DEFAULT_CONTENT_CHARSET);
} catch (UnsupportedEncodingException e) {
LOG.error("非法参数错误{}", e);
throw new IllegalArgumentException(e);
}
}
/**
* 系统使用UTF-8 解码
*
* @param content
* @param encoding
* @return
*/
public static String decode(final String content, final String encoding) {
try {
return URLDecoder.decode(content, encoding != null ? encoding : HTTP.DEFAULT_CONTENT_CHARSET);
} catch (UnsupportedEncodingException e) {
LOG.error("非法参数错误{}", e);
throw new IllegalArgumentException(e);
}
}
}
手机直冲类
package net.etongbao.vasp.tc.resources.onpay;
import static net.etongbao.common.utils.HttpClientDeliver.encode;
import static net.etongbao.common.utils.HttpClientDeliver.decode;
import static net.etongbao.common.utils.CheckUtils.isEmpty;
import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import net.etongbao.common.utils.HttpClientDeliver;
import net.etongbao.vasp.tc.resources.IDeliverGoods;
import org.springframework.stereotype.Component;
/**
* 手机充值类 直冲模式和预查询都可以使用此类
* 使用command来区分直冲和预查询模式
*
* 预查询模式优点:通过预查询模式,如遇见运营商维护以及没有对应商品等情况,
* 预查询接口会直接返回相关信息,这样的订单无需再次下单,可提高订单成功率 如果采用预查询模式, 则不能先预查询然后用“直冲请求”进行提交。
*
* 注意:预查询模式必须是在预查询(command=2)查询之后,再进行提交(command=1)。
*
* @author Fu Wei
*
*/
@Component
public class MobileRecharge extends AbstractOnpay implements IDeliverGoods {
//预查询模式
private String RES_URL_SELECT = "xxxxx";
//直冲模式
private String RES_URL = "xxxx";
// 预查询模式
public int command = 0;
public int getCommand() {
return command;
}
/**
* 设置域查询模式
* 直冲模式:command=0 直接进行充值 默认为直冲模式
* 预查询模式:先通过预查询(command=2)查询是否可下单,
* 返回可下单后, 在代理商商城对用户扣款后,再将原有信息再次提交(command=1)
*
* @param command
*/
public void setCommand(int command) {
this.command = command;
}
@Override
public Map execute(Map deliverMap) {
// 产品id
String prodid = String.valueOf(deliverMap.get("PDC_NO"));
// 代理商订单号
String orderid = String.valueOf(deliverMap.get("TSC_NO"));
// 充值号码
String mobilenum = String.valueOf(deliverMap.get("MOBILE_NUM"));
String mark = MARK;
StringBuilder sb = new StringBuilder(9);
StringBuilder sbStrEntity = null;
sb.append("prodid=").append(prodid).append(PARAMETER_SEPARATOR);
sb.append("agentid=").append(AGENT_ID).append(PARAMETER_SEPARATOR);
sb.append("backurl=").append(BACKURL).append(PARAMETER_SEPARATOR);
sb.append("returntype=").append(RETURN_TYPE).append(PARAMETER_SEPARATOR);
sb.append("orderid=").append(orderid).append(PARAMETER_SEPARATOR);
sb.append("mobilenum=").append(mobilenum).append(PARAMETER_SEPARATOR);
sb.append("source=").append(SOURCE).append(PARAMETER_SEPARATOR);
// 预查询模式
String url = RES_URL;
if (command > 0) {
sb.append("command=").append(command).append(PARAMETER_SEPARATOR);
url = RES_URL_SELECT;
}
mark = !isEmpty(mark)? encode(mark, ENCODING):mark;
sb.append("mark=").append(mark).append(PARAMETER_SEPARATOR);
sbStrEntity = new StringBuilder(sb);
sb.append("merchantKey=").append(MERCHANT_KEY);
LOG.debug("MERCHANT_KEY:{}",sb);
String verifystring = getVerifystring(sb.toString());
sbStrEntity.append("verifystring=").append(verifystring);
LOG.debug("客户端进行请求URL:{},参数串:{}", url, sbStrEntity.toString());
// 发货
InputStream in = HttpClientDeliver.clientPostDeliver(url, sbStrEntity.toString());
Map resMap = null;
// 获取响应map
Map xmlMap = xmlParse(in);
// 获取产品id
prodid = xmlMap.get("prodid");
// 获取代理商商城订单
orderid = xmlMap.get("orderid");
// 获取直冲接口平台订单号
String tranid = xmlMap.get("tranid");
// 获取返回码
String resultno = xmlMap.get("resultno");
// 获取预留字段
mark = xmlMap.get("mark");
// 获取响应摘要码
String retVerifystring = xmlMap.get("verifystring");
// 验证摘要串
if (checkVerifystring(prodid, orderid, tranid, resultno, mark, retVerifystring)) {
LOG.debug("订单号:{},响应摘要码验证成功", orderid);
resMap = new HashMap();
// 判断是否下单成功
if (resultno.equals("0000")) {
resMap.put("RES_TSC_NO", xmlMap.get("tranid"));
} else {
resMap.put("RES_TSC_NO", "");
}
resMap.put("DLVR_RET_CODE", resultno);
resMap.put("DLVR_RET_DESC", resultNoMap.get(resultno));
resMap.put("RES_TIME", new Date());
resMap.put("RESERVED", mark);
} else {
LOG.debug("订单号:{},响应摘要码验证失败", orderid);
}
return resMap;
}
/**
* 验证响应摘要串
*
* @param prodid
* @param orderid
* @param tranid
* @param resultno
* @param mark
* @param retVerifystring
* @return
*/
private boolean checkVerifystring(String prodid, String orderid, String tranid, String resultno, String mark,
String retVerifystring) {
StringBuilder sb = new StringBuilder(6);
sb.append("prodid=").append(prodid).append(PARAMETER_SEPARATOR);
sb.append("orderid=").append(orderid).append(PARAMETER_SEPARATOR);
sb.append("tranid=").append(tranid).append(PARAMETER_SEPARATOR);
sb.append("resultno=").append(resultno).append(PARAMETER_SEPARATOR);
mark = !isEmpty(mark)? decode(mark, ENCODING):mark;
sb.append("mark=").append(mark).append(PARAMETER_SEPARATOR);
sb.append("merchantKey=").append(MERCHANT_KEY);
return getVerifystring(sb.toString()).equals(retVerifystring);
}
}
抽象 AbstractOnpay.java
package net.etongbao.vasp.tc.resources.onpay;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import net.etongbao.common.utils.HttpClientDeliver;
import net.etongbao.common.utils.KeyedDigestMD5;
import net.etongbao.vasp.tc.resources.IDeliverGoods;
import static net.etongbao.common.utils.CheckUtils.isEmpty;
/**
* 发货类
*
* @author Fu Wei
*
*/
public abstract class AbstractOnpay {
public static final String PARAMETER_SEPARATOR = "&";
public static final String ENCODING = "UTF-8";
public static final String DECODING = "UTF-8";
public static final Logger LOG = LoggerFactory.getLogger(AbstractOnpay.class);
// 代理商ID 代理商在19pay代理平台的登录名
String AGENT_ID = "xxxxx";
// 直冲请求返回url 非空(当returntype为2时可为空)
String BACKURL = "";
// 返回类型 1表示post返回 2表示返回XML信息
String RETURN_TYPE = "2";
// 预留字段 预留字段,代理商系统返回时原样带回
String MARK = "";
// 加密串
String MERCHANT_KEY = "xxxxxx";
// 代理商来源 代理商商城请填写esales
String SOURCE = "esales";
Map resultNoMap = new HashMap();
public AbstractOnpay() {
resultNoMap.put("0000", "下单成功");
resultNoMap.put("0001", "支付失败");
resultNoMap.put("0999", "未开通直冲功能");
resultNoMap.put("1000", "下单失败,未扣款,重新提交订单");
resultNoMap.put("1001", "传入参数不完整");
resultNoMap.put("1002", "验证摘要串验证失败");
resultNoMap.put("1022", "充值号码格式错误 ");
resultNoMap.put("1003", "代理商验证失败");
resultNoMap.put("1004", "代理商未激活");
resultNoMap.put("1005", "没有对应充值产品");
resultNoMap.put("1006", "系统异常,请稍后重试");
resultNoMap.put("1007", "账户余额不足");
resultNoMap.put("1016", "交易密码验证错误,请联系管理员 ");
resultNoMap.put("1008", "此产品超出当天限额 ,请联系业务人员");
resultNoMap.put("1009", "没有对应订单");
resultNoMap.put("1010", "产品与手机号不匹配");
resultNoMap.put("1011", "定单号不允许重复");
resultNoMap.put("1012", "IP地址不符合要求");
resultNoMap.put("1013", "运营商系统升级,暂不能充值");
resultNoMap.put("1015", "无法查到对应号段");
resultNoMap.put("1017", "话费新加的充值限制,同一个号码10秒内只能充值一次");
}
/**
* 获取节点元素
*
* @param in
* @return
*/
protected Element getXmlElement(InputStream in) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(in);
// 获得根节点StuInfo
Element el = doc.getDocumentElement();
return el;
} catch (DOMException e) {
LOG.error("DOM错误", e);
} catch (ParserConfigurationException e) {
LOG.error("DocumentBuilder 创建失败", e);
} catch (SAXException e) {
LOG.error("XML文档数据格式验证失败", e);
} catch (IOException e) {
LOG.error("流操作失败", e);
}
return null;
}
/**
* 解析发货响应xml
*
* @param in
* @return
*/
protected Map xmlParse(InputStream in) {
Map xmlMap = new HashMap();
Element el = getXmlElement(in);
NodeList nodeList = el.getElementsByTagName("item");
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
NamedNodeMap nodeMap = node.getAttributes();
String name = nodeMap.getNamedItem("name").getNodeValue();
String value = nodeMap.getNamedItem("value").getNodeValue();
if (name.equals("mark") && !isEmpty(value)) {
value = HttpClientDeliver.decode(value,DECODING);
}
xmlMap.put(name, value);
}
return xmlMap;
}
/**
* 获取验证摘要串
*
* @param merchantKey 加密串
* @param srcString 源串
* @return
*/
protected static String getVerifystring(String strSrc) {
return KeyedDigestMD5.getKeyedDigest(strSrc, "");
}
}
发货接口
package net.etongbao.vasp.tc.resources;
import java.util.Map;
/**
* 发货接口
*
* @author Fu Wei
*
*/
public interface IDeliverGoods {
/**执行接口操作
*
* @param deliverMap
*/
public Map execute(Map deliverMap);
}