案例30-在线支付
1 案例分析
1 支付分析
2 在线支付分析
常见的第三方支付平台:支付宝 国付宝(很难用) 微信 连连支付(这个支付很牛) 易宝支付
PTB公司: 拍拍贷 陆金所 温商贷 玖富 点融网 都是使用连连支付
第三方支付平台公司的盈利模式:
1:接口接入费用
2:取钱手续费
2 代码实现
1 order_info.jsp代码
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>会员登录</title> <link rel="stylesheet" href="css/bootstrap.min.css" type="text/css" /> <script src="js/jquery-1.11.3.min.js" type="text/javascript"></script> <script src="js/bootstrap.min.js" type="text/javascript"></script> <!-- 引入自定义css文件 style.css --> <link rel="stylesheet" href="css/style.css" type="text/css" /> <style> body { margin-top: 20px; margin: 0 auto; } .carousel-inner .item img { width: 100%; height: 300px; } </style> <script type="text/javascript"> function confirmOrder(){ //提交表单 $("#orderForm").submit(); } </script> </head> <body> <!-- 引入header.jsp --> <jsp:include page="/header.jsp"></jsp:include> <div class="container"> <div class="row"> <div style="margin: 0 auto; margin-top: 10px; width: 950px;"> <strong>订单详情</strong> <table class="table table-bordered"> <tbody> <tr class="warning"> <th colspan="5">订单编号:${order.oid }</th> </tr> <tr class="warning"> <th>图片</th> <th>商品</th> <th>价格</th> <th>数量</th> <th>小计</th> </tr> <c:forEach items="${order.orderItems }" var="orderItem"> <tr class="active"> <td width="60" width="40%"> <img src="${pageContext.request.contextPath }/${orderItem.product.pimage}" width="70" height="60"> </td> <td width="30%"><a target="_blank">${orderItem.product.pname}</a></td> <td width="20%">¥${orderItem.product.shop_price}</td> <td width="10%">${orderItem.count}</td> <td width="15%"><span class="subtotal">¥${orderItem.subtotal }</span></td> </tr> </c:forEach> </tbody> </table> </div> <div style="text-align: right; margin-right: 120px;"> 商品金额: <strong style="color: #ff6600;">¥${order.total }元</strong> </div> </div> <div> <hr /> <form id="orderForm" class="form-horizontal" action="${pageContext.request.contextPath }/product" method="post" style="margin-top: 5px; margin-left: 150px;"> <!-- method的名字 通过表单提交 --> <input type="hidden" name="method" value="confirmOrder"> <!-- 传递订单oid --> <input type="hidden" name="oid" value="${order.oid }"> <div class="form-group"> <label for="username" class="col-sm-1 control-label">地址</label> <div class="col-sm-5"> <input type="text" class="form-control" id="address" name="address" value=""> </div> </div> <div class="form-group"> <label for="inputPassword3" class="col-sm-1 control-label">收货人</label> <div class="col-sm-5"> <input type="text" class="form-control" id="inputPassword3" name="name" placeholder="请输收货人" value="${user.name }"> </div> </div> <div class="form-group"> <label for="confirmpwd" class="col-sm-1 control-label">电话</label> <div class="col-sm-5"> <input type="text" class="form-control" id="confirmpwd" name="telephone" placeholder="请输入联系方式" value="${user.telephone }"> </div> </div> <hr /> <div style="margin-top: 5px; margin-left: 150px;"> <strong>选择银行:</strong> <p> <br /> <input type="radio" name="pd_FrpId" value="ICBC-NET-B2C" checked="checked" />工商银行 <img src="./bank_img/icbc.bmp" align="middle" /> <input type="radio" name="pd_FrpId" value="BOC-NET-B2C" />中国银行 <img src="./bank_img/bc.bmp" align="middle" /> <input type="radio" name="pd_FrpId" value="ABC-NET-B2C" />农业银行 <img src="./bank_img/abc.bmp" align="middle" /> <br /> <br /> <input type="radio" name="pd_FrpId" value="BOCO-NET-B2C" />交通银行 <img src="./bank_img/bcc.bmp" align="middle" /> <input type="radio" name="pd_FrpId" value="PINGANBANK-NET" />平安银行 <img src="./bank_img/pingan.bmp" align="middle" /> <input type="radio" name="pd_FrpId" value="CCB-NET-B2C" />建设银行 <img src="./bank_img/ccb.bmp" align="middle" /> <br /> <br /> <input type="radio" name="pd_FrpId" value="CEB-NET-B2C" />光大银行 <img src="./bank_img/guangda.bmp" align="middle" /> <input type="radio" name="pd_FrpId" value="CMBCHINA-NET-B2C" />招商银行 <img src="./bank_img/cmb.bmp" align="middle" /> </p> <hr /> <p style="text-align: right; margin-right: 100px;"> <a href="javascript:;" onclick="confirmOrder()"> <img src="./images/finalbutton.gif" width="204" height="51" border="0" /> </a> </p> <hr /> </div> </form> </div> </div> <!-- 引入footer.jsp --> <jsp:include page="/footer.jsp"></jsp:include> </body> </html>
2 ProductServlet代码
//确认订单---更新收获人信息+在线支付 public void confirmOrder(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1、更新收货人信息 Map<String, String[]> properties = request.getParameterMap(); Order order = new Order(); try { BeanUtils.populate(order, properties); } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } ProductService service = new ProductService(); service.updateOrderAdrr(order); //2、在线支付 /*if(pd_FrpId.equals("ABC-NET-B2C")){ //接入农行的接口 }else if(pd_FrpId.equals("ICBC-NET-B2C")){ //接入工行的接口 }*/ //....... //只接入一个接口,这个接口已经集成所有的银行接口了 ,这个接口是第三方支付平台提供的 //接入的是易宝支付 // 获得 支付必须基本数据 String orderid = request.getParameter("oid"); //String money = order.getTotal()+"";//支付金额 String money = "0.01";//支付金额 // 银行 String pd_FrpId = request.getParameter("pd_FrpId"); // 发给支付公司需要哪些数据 String p0_Cmd = "Buy"; String p1_MerId = ResourceBundle.getBundle("merchantInfo").getString("p1_MerId"); String p2_Order = orderid; String p3_Amt = money; String p4_Cur = "CNY"; String p5_Pid = ""; String p6_Pcat = ""; String p7_Pdesc = ""; // 支付成功回调地址 ---- 第三方支付公司会访问、用户访问 // 第三方支付可以访问网址 String p8_Url = ResourceBundle.getBundle("merchantInfo").getString("callback"); String p9_SAF = ""; String pa_MP = ""; String pr_NeedResponse = "1"; // 加密hmac 需要密钥 String keyValue = ResourceBundle.getBundle("merchantInfo").getString( "keyValue"); String hmac = PaymentUtil.buildHmac(p0_Cmd, p1_MerId, p2_Order, p3_Amt, p4_Cur, p5_Pid, p6_Pcat, p7_Pdesc, p8_Url, p9_SAF, pa_MP, pd_FrpId, pr_NeedResponse, keyValue); String url = "https://www.yeepay.com/app-merchant-proxy/node?pd_FrpId="+pd_FrpId+ "&p0_Cmd="+p0_Cmd+ "&p1_MerId="+p1_MerId+ "&p2_Order="+p2_Order+ "&p3_Amt="+p3_Amt+ "&p4_Cur="+p4_Cur+ "&p5_Pid="+p5_Pid+ "&p6_Pcat="+p6_Pcat+ "&p7_Pdesc="+p7_Pdesc+ "&p8_Url="+p8_Url+ "&p9_SAF="+p9_SAF+ "&pa_MP="+pa_MP+ "&pr_NeedResponse="+pr_NeedResponse+ "&hmac="+hmac; //重定向到第三方支付平台 response.sendRedirect(url); }
3 ProductService代码
// 跟新收货人信息 public void updateOrderAdrr(Order order) { ProductDao dao = new ProductDao(); try { dao.updateOrderAdrr(order); } catch (SQLException e) { e.printStackTrace(); } } //跟新订单支付状态 public void updateOrderState(String r6_Order) { ProductDao dao = new ProductDao(); try { dao.updateOrderState(r6_Order); } catch (SQLException e) { e.printStackTrace(); } }
4 ProductDao代码
//跟新收货人信息 public void updateOrderAdrr(Order order) throws SQLException { QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource()); String sql = "update orders set address=?,name=?,telephone=? where oid=?"; runner.update(sql, order.getAddress(),order.getName(),order.getTelephone(),order.getOid()); } //跟新用户支付状态 public void updateOrderState(String r6_Order) throws SQLException { QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource()); String sql = "update orders set state=? where oid=?"; runner.update(sql, 1,r6_Order); }
5 CallBackServlet代码
package www.test.web.servlet; import java.io.IOException; import java.util.ResourceBundle; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.itheima.service.ProductService; import com.itheima.utils.PaymentUtil; public class CallbackServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获得回调所有数据 String p1_MerId = request.getParameter("p1_MerId"); String r0_Cmd = request.getParameter("r0_Cmd"); String r1_Code = request.getParameter("r1_Code"); String r2_TrxId = request.getParameter("r2_TrxId"); String r3_Amt = request.getParameter("r3_Amt"); String r4_Cur = request.getParameter("r4_Cur"); String r5_Pid = request.getParameter("r5_Pid"); //订单编号 String r6_Order = request.getParameter("r6_Order"); String r7_Uid = request.getParameter("r7_Uid"); String r8_MP = request.getParameter("r8_MP"); String r9_BType = request.getParameter("r9_BType"); String rb_BankId = request.getParameter("rb_BankId"); String ro_BankOrderId = request.getParameter("ro_BankOrderId"); String rp_PayDate = request.getParameter("rp_PayDate"); String rq_CardNo = request.getParameter("rq_CardNo"); String ru_Trxtime = request.getParameter("ru_Trxtime"); // 身份校验 --- 判断是不是支付公司通知你 String hmac = request.getParameter("hmac"); String keyValue = ResourceBundle.getBundle("merchantInfo").getString( "keyValue"); // 自己对上面数据进行加密 --- 比较支付公司发过来hamc boolean isValid = PaymentUtil.verifyCallback(hmac, p1_MerId, r0_Cmd, r1_Code, r2_TrxId, r3_Amt, r4_Cur, r5_Pid, r6_Order, r7_Uid, r8_MP, r9_BType, keyValue); if (isValid) { // 响应数据有效 if (r9_BType.equals("1")) { //修改订单状态 ProductService service= new ProductService(); service.updateOrderState(r6_Order); // 浏览器重定向 response.setContentType("text/html;charset=utf-8"); response.getWriter().println("<h1>付款成功!等待商城进一步操作!等待收货...</h1>"); } else if (r9_BType.equals("2")) { //真正开发的时候有外网地址,代码写在这里。 // 服务器点对点 --- 支付公司通知你 System.out.println("付款成功!"); // 修改订单状态 为已付款 // 回复支付公司 response.getWriter().print("success"); } } else { // 数据无效 System.out.println("数据被篡改!"); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
3 在线支付工具类代码
1 CallBackServlet
package www.test.servlet; import java.io.IOException; import java.util.ResourceBundle; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.itcast.utils.PaymentUtil; /** * 该Servlet会在支付成功后 进行调用----- 支付公司 、客户 * * @author seawind * */ public class CallbackServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获得回调所有数据 String p1_MerId = request.getParameter("p1_MerId"); String r0_Cmd = request.getParameter("r0_Cmd"); String r1_Code = request.getParameter("r1_Code"); String r2_TrxId = request.getParameter("r2_TrxId"); String r3_Amt = request.getParameter("r3_Amt"); String r4_Cur = request.getParameter("r4_Cur"); String r5_Pid = request.getParameter("r5_Pid"); String r6_Order = request.getParameter("r6_Order"); String r7_Uid = request.getParameter("r7_Uid"); String r8_MP = request.getParameter("r8_MP"); String r9_BType = request.getParameter("r9_BType"); String rb_BankId = request.getParameter("rb_BankId"); String ro_BankOrderId = request.getParameter("ro_BankOrderId"); String rp_PayDate = request.getParameter("rp_PayDate"); String rq_CardNo = request.getParameter("rq_CardNo"); String ru_Trxtime = request.getParameter("ru_Trxtime"); // 身份校验 --- 判断是不是支付公司通知你 String hmac = request.getParameter("hmac"); String keyValue = ResourceBundle.getBundle("merchantInfo").getString( "keyValue"); // 自己对上面数据进行加密 --- 比较支付公司发过来hamc boolean isValid = PaymentUtil.verifyCallback(hmac, p1_MerId, r0_Cmd, r1_Code, r2_TrxId, r3_Amt, r4_Cur, r5_Pid, r6_Order, r7_Uid, r8_MP, r9_BType, keyValue); if (isValid) { // 响应数据有效 if (r9_BType.equals("1")) { // 浏览器重定向 response.setContentType("text/html;charset=utf-8"); response.getWriter().println("<h1>付款成功!等待商城进一步操作!等待收货...</h1>"); } else if (r9_BType.equals("2")) { // 服务器点对点 --- 支付公司通知你 System.out.println("付款成功!"); // 修改订单状态 为已付款 // 回复支付公司 response.getWriter().print("success"); } } else { // 数据无效 System.out.println("数据被篡改!"); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
2 PaymentUtils
package www.test.utils; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; public class PaymentUtil { private static String encodingCharset = "UTF-8"; /** * 生成hmac方法 * * @param p0_Cmd 业务类型 * @param p1_MerId 商户编号 * @param p2_Order 商户订单号 * @param p3_Amt 支付金额 * @param p4_Cur 交易币种 * @param p5_Pid 商品名称 * @param p6_Pcat 商品种类 * @param p7_Pdesc 商品描述 * @param p8_Url 商户接收支付成功数据的地址 * @param p9_SAF 送货地址 * @param pa_MP 商户扩展信息 * @param pd_FrpId 银行编码 * @param pr_NeedResponse 应答机制 * @param keyValue 商户密钥 * @return */ public static String buildHmac(String p0_Cmd,String p1_MerId, String p2_Order, String p3_Amt, String p4_Cur,String p5_Pid, String p6_Pcat, String p7_Pdesc,String p8_Url, String p9_SAF,String pa_MP,String pd_FrpId, String pr_NeedResponse,String keyValue) { StringBuilder sValue = new StringBuilder(); // 业务类型 sValue.append(p0_Cmd); // 商户编号 sValue.append(p1_MerId); // 商户订单号 sValue.append(p2_Order); // 支付金额 sValue.append(p3_Amt); // 交易币种 sValue.append(p4_Cur); // 商品名称 sValue.append(p5_Pid); // 商品种类 sValue.append(p6_Pcat); // 商品描述 sValue.append(p7_Pdesc); // 商户接收支付成功数据的地址 sValue.append(p8_Url); // 送货地址 sValue.append(p9_SAF); // 商户扩展信息 sValue.append(pa_MP); // 银行编码 sValue.append(pd_FrpId); // 应答机制 sValue.append(pr_NeedResponse); return PaymentUtil.hmacSign(sValue.toString(), keyValue); } /** * 返回校验hmac方法 * * @param hmac 支付网关发来的加密验证码 * @param p1_MerId 商户编号 * @param r0_Cmd 业务类型 * @param r1_Code 支付结果 * @param r2_TrxId 易宝支付交易流水号 * @param r3_Amt 支付金额 * @param r4_Cur 交易币种 * @param r5_Pid 商品名称 * @param r6_Order 商户订单号 * @param r7_Uid 易宝支付会员ID * @param r8_MP 商户扩展信息 * @param r9_BType 交易结果返回类型 * @param keyValue 密钥 * @return */ public static boolean verifyCallback(String hmac, String p1_MerId, String r0_Cmd, String r1_Code, String r2_TrxId, String r3_Amt, String r4_Cur, String r5_Pid, String r6_Order, String r7_Uid, String r8_MP, String r9_BType, String keyValue) { StringBuilder sValue = new StringBuilder(); // 商户编号 sValue.append(p1_MerId); // 业务类型 sValue.append(r0_Cmd); // 支付结果 sValue.append(r1_Code); // 易宝支付交易流水号 sValue.append(r2_TrxId); // 支付金额 sValue.append(r3_Amt); // 交易币种 sValue.append(r4_Cur); // 商品名称 sValue.append(r5_Pid); // 商户订单号 sValue.append(r6_Order); // 易宝支付会员ID sValue.append(r7_Uid); // 商户扩展信息 sValue.append(r8_MP); // 交易结果返回类型 sValue.append(r9_BType); String sNewString = PaymentUtil.hmacSign(sValue.toString(), keyValue); return sNewString.equals(hmac); } /** * @param aValue * @param aKey * @return */ public static String hmacSign(String aValue, String aKey) { byte k_ipad[] = new byte[64]; byte k_opad[] = new byte[64]; byte keyb[]; byte value[]; try { keyb = aKey.getBytes(encodingCharset); value = aValue.getBytes(encodingCharset); } catch (UnsupportedEncodingException e) { keyb = aKey.getBytes(); value = aValue.getBytes(); } Arrays.fill(k_ipad, keyb.length, 64, (byte) 54); Arrays.fill(k_opad, keyb.length, 64, (byte) 92); for (int i = 0; i < keyb.length; i++) { k_ipad[i] = (byte) (keyb[i] ^ 0x36); k_opad[i] = (byte) (keyb[i] ^ 0x5c); } MessageDigest md = null; try { md = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { return null; } md.update(k_ipad); md.update(value); byte dg[] = md.digest(); md.reset(); md.update(k_opad); md.update(dg, 0, 16); dg = md.digest(); return toHex(dg); } public static String toHex(byte input[]) { if (input == null) return null; StringBuffer output = new StringBuffer(input.length * 2); for (int i = 0; i < input.length; i++) { int current = input[i] & 0xff; if (current < 16) output.append("0"); output.append(Integer.toString(current, 16)); } return output.toString(); } /** * * @param args * @param key * @return */ public static String getHmac(String[] args, String key) { if (args == null || args.length == 0) { return (null); } StringBuffer str = new StringBuffer(); for (int i = 0; i < args.length; i++) { str.append(args[i]); } return (hmacSign(str.toString(), key)); } /** * @param aValue * @return */ public static String digest(String aValue) { aValue = aValue.trim(); byte value[]; try { value = aValue.getBytes(encodingCharset); } catch (UnsupportedEncodingException e) { value = aValue.getBytes(); } MessageDigest md = null; try { md = MessageDigest.getInstance("SHA"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return null; } return toHex(md.digest(value)); } // public static void main(String[] args) { // System.out.println(hmacSign("AnnulCard1000043252120080620160450.0http://localhost/SZXpro/callback.asp杩?4564868265473632445648682654736324511","8UPp0KE8sq73zVP370vko7C39403rtK1YwX40Td6irH216036H27Eb12792t")); // } }
3 PayServlet
package www.test.servlet; import java.io.IOException; import java.util.ResourceBundle; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.itcast.utils.PaymentUtil; public class PayServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获得 支付必须基本数据 String orderid = request.getParameter("orderid"); String money = request.getParameter("money"); // 银行 String pd_FrpId = request.getParameter("pd_FrpId"); // 发给支付公司需要哪些数据 String p0_Cmd = "Buy"; String p1_MerId = ResourceBundle.getBundle("merchantInfo").getString("p1_MerId"); String p2_Order = orderid; String p3_Amt = money; String p4_Cur = "CNY"; String p5_Pid = ""; String p6_Pcat = ""; String p7_Pdesc = ""; // 支付成功回调地址 ---- 第三方支付公司会访问、用户访问 // 第三方支付可以访问网址 String p8_Url = ResourceBundle.getBundle("merchantInfo").getString("callback"); String p9_SAF = ""; String pa_MP = ""; String pr_NeedResponse = "1"; // 加密hmac 需要密钥 String keyValue = ResourceBundle.getBundle("merchantInfo").getString( "keyValue"); String hmac = PaymentUtil.buildHmac(p0_Cmd, p1_MerId, p2_Order, p3_Amt, p4_Cur, p5_Pid, p6_Pcat, p7_Pdesc, p8_Url, p9_SAF, pa_MP, pd_FrpId, pr_NeedResponse, keyValue); String url = "https://www.yeepay.com/app-merchant-proxy/node?pd_FrpId="+pd_FrpId+ "&p0_Cmd="+p0_Cmd+ "&p1_MerId="+p1_MerId+ "&p2_Order="+p2_Order+ "&p3_Amt="+p3_Amt+ "&p4_Cur="+p4_Cur+ "&p5_Pid="+p5_Pid+ "&p6_Pcat="+p6_Pcat+ "&p7_Pdesc="+p7_Pdesc+ "&p8_Url="+p8_Url+ "&p9_SAF="+p9_SAF+ "&pa_MP="+pa_MP+ "&pr_NeedResponse="+pr_NeedResponse+ "&hmac="+hmac; //重定向到第三方支付平台 response.sendRedirect(url); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
4 merchantInfo.properties
p1_MerId=10001126856
keyValue=69cl522AV6q613Ii4W6u8K6XuW8vM1N6bFgyv769220IuYe9u37N4y7rI4Pl
callback=http://localhost:8080/WEBTestShop31/callback