连连支付的官方sdk文件有点多,但是看起来比较容易理解。逻辑上大体上跟支付宝支付差不多,配置也差不多,直接贴代码。不同的是要接入连连支付需要事先与连连支付人员取得联系,签订合同后他们会给你一个商户号,然后登陆https://b.lianlianpay.com/trader/login.htm,并配置一些基本配置。
package com.llpay.client.config;
/**
* 连连支付 商户配置信息
* @author guoyx e-mail:[email protected]
* @date:2013-6-25 下午01:45:40
* @version :1.0
*
*/
public interface PartnerConfig{
// 银通公钥 必填
String YT_PUB_KEY = "";
// 商户私钥 必填
String TRADER_PRI_KEY = "";
// MD5 KEY 这个随意
String MD5_KEY = "201408071000001546_test_20140815";//此处采用了rsa加签方式,
// 接收异步通知地址 必填
String NOTIFY_URL = "";
// 支付结束后返回地址 必填
String URL_RETURN = "";
// 商户编号 必填
String OID_PARTNER = "";
// 签名方式 RSA或MD5 一般就用RSA
String SIGN_TYPE = "RSA";
// 接口版本号,固定1.0
String VERSION = "1.0";
// 业务类型,连连支付根据商户业务为商户开设的业务类型; (101001:虚拟商品销售、109001:实物商品销售、108001:外部账户充值)
String BUSI_PARTNER = "101001";
}
@Controller
public class LLOrderController {
Logger log = Logger.getLogger(LLOrderController.class);
@Autowired
private HttpServletRequest request;
@Autowired
private ReqProductService reqproductService;
@Autowired
private TransreqService transreqService;
@Autowired
private AddressService addressService;
@Autowired
private OrderService orderService;
/**
* 异步通知
* @return
*/
@RequestMapping("llpaynotify")
@ResponseBody
public String llpaynotify(HttpServletRequest request,HttpServletResponse resp){
// resp.setCharacterEncoding("UTF-8");
log.info("进入连连支付异步通知数据接收处理");
RetBean retBean = new RetBean();
String reqStr = LLPayUtil.readReqStr(request);
if (LLPayUtil.isnull(reqStr))
{
retBean.setRet_code("9999");
retBean.setRet_msg("交易失败");
return JSON.toJSONString(retBean);
}
log.info("接收连连支付异步通知数据:【" + reqStr + "】");
try
{
if (!LLPayUtil.checkSign(reqStr, PartnerConfig.YT_PUB_KEY,
PartnerConfig.MD5_KEY))
{
retBean.setRet_code("9999");
retBean.setRet_msg("交易失败");
log.info("连连支付异步通知验签失败");
return JSON.toJSONString(retBean);
}
} catch (Exception e)
{
log.info("连连支付异步通知报文解析异常:" + e);
retBean.setRet_code("9999");
retBean.setRet_msg("交易失败");
return JSON.toJSONString(retBean);
}
log.info("连连支付异步通知数据接收处理成功");
//解析异步通知对象
PayDataBean payDataBean = JSON.parseObject(reqStr, PayDataBean.class);
// TODO:更新订单,发货等后续处理
if("SUCCESS".equalsIgnoreCase(payDataBean.getResult_pay())){
try {
dologic(request,payDataBean);
retBean.setRet_code("0000");
retBean.setRet_msg("交易成功");
} catch (Exception e) {
retBean.setRet_code("9999");
retBean.setRet_msg("交易失败");
log.error(e.getMessage());
}
}else{
retBean.setRet_code("9999");
retBean.setRet_msg("交易失败");
}
return JSON.toJSONString(retBean);
}
private void dologic(HttpServletRequest request,PayDataBean payDataBean) throws Exception{
//商户系统订单号
String out_trade_no = payDataBean.getNo_order();
//连连支付交易号
String trade_no = payDataBean.getOid_paybill();
//金额
String total_amount = payDataBean.getMoney_order();
// //app_id
// String app_id = request.getParameter("app_id");
Transreq transreq = transreqService.selectByPrimaryKey(out_trade_no);//购买流水
if(transreq == null){
throw new Exception("未查询到购买流水信息,商户逻辑处理失败,订单号为:"+out_trade_no);
}
if(!IDict.REQ_STATUS.REQ_STATUS_DFK.equals(transreq.getStatus())){//判断状态
throw new Exception("该购买流水信息状态不为待付款,商户逻辑处理失败,订单号为:"+out_trade_no);
}
if(transreq.getAmt().subtract(new BigDecimal(total_amount)).compareTo(new BigDecimal("0.1"))>0){//判断金额
throw new Exception("银行卡支付支付的金额与订单中的金额不一致,商户逻辑处理失败,订单号为:"+out_trade_no);
};
// if(!AlipayConfig.app_id.equals(app_id)){//判断appid是否相同
// return ;
//
// }
Transreq uploadtransreq = transreqService.selectByPrimaryKey(transreq.getAssoSerial());
if(uploadtransreq == null){
throw new Exception("银行卡支付异步回调时未找到与订单信息相关的上传商品的信息,商户逻辑处理失败,订单号为:"+out_trade_no);
}
if(!IDict.REQ_STATUS.REQ_STATUS_SUCCESS.equals(uploadtransreq.getStatus())){
throw new Exception("银行卡支付异步回调时找到的与订单信息相关的上传商品的信息状态不正确,商户逻辑处理失败,订单号为:"+out_trade_no);
}
try {
orderService.pay(transreq, uploadtransreq,trade_no);
} catch (Exception e) {
throw new Exception("数据更新失败,订单号为:"+out_trade_no);
}
return ;
}
/**
* 同步通知
* @return
*/
@RequestMapping("llpayreturn")
public String llpayreturn(Model model,HttpServletRequest request,HttpServletResponse resp){
log.info("进入连连支付同步通知数据接收处理");
RetBean retBean = new RetBean();
/*从 request 中获取请求参数有两种情况
1.从 get 方法中获取请求参数
get 方法的请求参数存放在 getQueryString() 方法中,不需要从 getInputStream() 中获取
2.从 post 方法中获取请求参数
post 方法的参数存放在 流当中需要从 getInputStream() 中获取。*/
// String reqStr = LLPayUtil.readReqStr(request);//
//String reqStr = request.getQueryString();
Map params = new HashMap();
Map requestParams = request.getParameterMap();
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
//乱码解决,这段代码在出现乱码时使用
// try {
// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
// } catch (UnsupportedEncodingException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
params.put(name, valueStr);
}
JSONObject jsonobj = (JSONObject) JSONObject.toJSON(params);
String reqStr = jsonobj.toJSONString();
if (LLPayUtil.isnull(reqStr))
{
retBean.setRet_code("9999");
retBean.setRet_msg("交易失败");
model.addAttribute("retBean",retBean);
return "llpayreturn_url";
}
log.info("接收连连支付同步通知数据:【" + reqStr + "】");
try
{
if (!LLPayUtil.checkSign(reqStr, PartnerConfig.YT_PUB_KEY,
PartnerConfig.MD5_KEY))
{
retBean.setRet_code("9999");
retBean.setRet_msg("交易失败");
log.info("连连支付同步通知验签失败");
model.addAttribute("retBean",retBean);
return "llpayreturn_url";
}
} catch (Exception e)
{
log.info("连连支付同步通知报文解析异常:" + e);
retBean.setRet_code("9999");
retBean.setRet_msg("交易失败");
model.addAttribute("retBean",retBean);
return "llpayreturn_url";
}
retBean.setRet_code("0000");
retBean.setRet_msg("交易成功");
log.info("连连支付同步通知数据接收处理成功");
model.addAttribute("retBean",retBean);
return "llpayreturn_url";
}
/**
* 连连支付
* @return
*/
@RequestMapping("dobuyByLL")
public String dobuyByLL(Model model,HttpServletRequest request,HttpServletResponse response){
User u = (User) request.getSession().getAttribute("user");
if(u==null||DataUtil.isNullStr(u.getUserName())){
return "login";
}
String flag = request.getParameter(ITag.Flag);
Map map = null;
if("0".equals(flag)){//表示第一次生成订单
map = orderService.generateOrder(request);
}else if("1".equals(flag)){//表示订单之前已经生成,现在来付款
map = orderService.getOrderinfo(request);
}
if(map == null){
model.addAttribute(ITag.ReturnCode, "-1");
model.addAttribute(ITag.ErrorMessage, "该产品不存在或者已经被其他买家购买");
return "trade.page.pay";
}
sendToLLpay(request,map);
return "gotoPlainPay";
}
private void sendToLLpay(HttpServletRequest req, Map map) {
Transreq transreq = (Transreq) map.get("transreq");
ReqProduct reqproduct = (ReqProduct) map.get("reqproduct");
// 创建订单
OrderInfo order = createOrder(transreq,reqproduct);
// 构造支付请求对象
PaymentInfo paymentInfo = new PaymentInfo();
paymentInfo.setVersion(PartnerConfig.VERSION);
paymentInfo.setOid_partner(PartnerConfig.OID_PARTNER);
paymentInfo.setUser_id(String.valueOf(transreq.getPrddestUserid()));//买家id
paymentInfo.setSign_type(PartnerConfig.SIGN_TYPE);
paymentInfo.setBusi_partner(PartnerConfig.BUSI_PARTNER);
paymentInfo.setNo_order(order.getNo_order());
paymentInfo.setDt_order(order.getDt_order());
paymentInfo.setName_goods(order.getName_goods());
paymentInfo.setInfo_order(order.getInfo_order());
paymentInfo.setMoney_order(order.getMoney_order());
paymentInfo.setNotify_url(PartnerConfig.NOTIFY_URL);
paymentInfo.setUrl_return(PartnerConfig.URL_RETURN);
paymentInfo.setUserreq_ip(LLPayUtil.getIpAddr(req));
paymentInfo.setUrl_order("");
paymentInfo.setValid_order("10080");// 单位分钟,可以为空,默认7天
paymentInfo.setTimestamp(LLPayUtil.getCurrentDateTimeStr());
paymentInfo.setRisk_item(createRiskItem(transreq,req));
// 加签名
String sign = LLPayUtil.addSign(JSON.parseObject(JSON
.toJSONString(paymentInfo)), PartnerConfig.TRADER_PRI_KEY,
PartnerConfig.MD5_KEY);
paymentInfo.setSign(sign);
req.setAttribute("version", paymentInfo.getVersion());
req.setAttribute("oid_partner", paymentInfo.getOid_partner());
req.setAttribute("user_id", paymentInfo.getUser_id());
req.setAttribute("sign_type", paymentInfo.getSign_type());
req.setAttribute("busi_partner", paymentInfo.getBusi_partner());
req.setAttribute("no_order", paymentInfo.getNo_order());
req.setAttribute("dt_order", paymentInfo.getDt_order());
req.setAttribute("name_goods", paymentInfo.getName_goods());
req.setAttribute("info_order", paymentInfo.getInfo_order());
req.setAttribute("money_order", paymentInfo.getMoney_order());
req.setAttribute("notify_url", paymentInfo.getNotify_url());
req.setAttribute("url_return", paymentInfo.getUrl_return());
req.setAttribute("userreq_ip", paymentInfo.getUserreq_ip());
req.setAttribute("url_order", paymentInfo.getUrl_order());
req.setAttribute("valid_order", paymentInfo.getValid_order());
req.setAttribute("timestamp", paymentInfo.getTimestamp());
req.setAttribute("sign", paymentInfo.getSign());
req.setAttribute("risk_item", paymentInfo.getRisk_item());
req.setAttribute("req_url", ServerURLConfig.PAY_URL);
}
/**
* 模拟商户创建订单
* @param req
* @return
*/
private OrderInfo createOrder(Transreq transreq,ReqProduct product)
{
OrderInfo orderInfo = new OrderInfo();
orderInfo.setNo_order(transreq.getSerialNo()); //
Date date = transreq.getTransTime();
String dateStr = DateUtil.getDateTime(date, "yyyyMMddHHmmss");
orderInfo.setDt_order(dateStr);//订单时间
DecimalFormat dft = new DecimalFormat("#.00");
String amt = dft.format(transreq.getAmt().doubleValue());
orderInfo.setMoney_order(amt);
orderInfo.setName_goods(product.getPrdName());
orderInfo.setInfo_order("用户购买" + product.getPrdName());
return orderInfo;
}
/**
* 根据连连支付风控部门要求的参数进行构造风控参数
* @return
*/
private String createRiskItem(Transreq transreq,HttpServletRequest req)
{
User user = (User) req.getSession().getAttribute("user");
JSONObject riskItemObj = new JSONObject();
riskItemObj.put("user_info_mercht_userno", String.valueOf(transreq.getPrddestUserid()));
riskItemObj.put("frms_ware_category", "1008");
if(user !=null){
String dateStr = DateUtil.getDateTime(user.getCreateAt(), "yyyyMMddHHmmss");
riskItemObj.put("user_info_dt_register",dateStr);
riskItemObj.put("user_info_bind_phone", user.getTelNumber());
}
return riskItemObj.toString();
}
}