SSH框架网上商城项目第21战之详解易宝支付的流程

这一节我们先写一个简单点的Demo来测试易宝支付的流程,熟悉这个流程后,再做实际的开发,因为是一个Demo,所以我没有考虑一些设计模式的东西,就是直接实现支付功能。实现支付功能需要易宝给我们提供的API。那么问题来了,使用第三方支付平台最主要的一件事就是获取该平台的API,我们首先得获取他们的API以及开发文档,然后才可以做进一步的开发。

1. 获取易宝的API

获取API的第一步,要在易宝上注册一个账号,这个账号是商家的账号,后面买家付款后,会将钱款存入该账号中,然后商家自己提取到银行卡,易宝在提取过程中收取一定的手续费。这就是易宝的盈利模式。但是注册成功需要前提,那就是自己得有一个网站,或者是一个公司,吧啦吧啦等东西,反正就是你得有资格申请,这点易宝会审核的,满足了才会允许你注册,才会给你提供他们的接口,不是所有人都可以注册的。我用的也是别人注册好的,我自己啥也没有……也没法注册……屌丝一个,大家懂的~但是一般在公司里开发的话,就不会存在这个问题,账号肯定都是有的,最重要的是要掌握开发流程和相关技术~

2. 测试支付流程

有了官方提供的API和技术文档后,就可以着手开发了,在这里主要写一个简单的demo来测试一下易宝支付的流程,demo的结构很简单,一个servlet,一个filter,两个jsp页面和一个加密的工具类。servlet与易宝服务器端打交道,我们做一些跟易宝接口相关的处理,filter是用来处理可能出现的中文乱码问题,两个jsp中一个是前台页面。
我们先来分析一下支付请求的过程,如下所示:

好了,下面我们具体分析一下demo中的相关代码:

2.1 前台测试页面

首先看一下前台页面index.jsp的具体代码

<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
 <head>

  <title>前台首页</title>
 </head>

 <body>
  <h1>在线支付演示</h1>
  <form action="${pageContext.request.contextPath }/servlet/PayServlet" method="post">
     此次购物订单编号<input type="text" name="p2_Order" /><br>
     money<input type="text" name="p3_Amt" value="0.01"/><br>
     工商银行<input type="radio" value="ICBC-NET" name="pd_FrpId">
     建设银行<input type="radio" value="CCB-NET" name="pd_FrpId"><br>
     <input type="submit" value="submit" />
     <input type="hidden" value="pay" name="status"/>
  </form>
 </body>
</html>

从上面的jsp页面中可以看出,这些input标签中的name属性值都很奇怪,pi_功能(i=0,1,2,…,9),当然i还有其他的值,这得参照易宝的官方文档,这些name表示相对应的属性,到时候会传到sevlet处理,关于这些属性值,我截了个图,如下:


  

这些参数名有些在实际项目中是前台传进来的,比如上面写的订单号,要付多少钱,这些在订单确认的时候都会带过去,那么其他参数,必填的话,需要在servlet里指定好,非必填字段的话,就可以为空,这里的空不是null,而是”“,后面servlet中会提到。
再看看两个银行中对应的value值也是固定的,易宝会提供它所支持的所有银行的value值,这些都是固定的,不能修改的。这里就写两个银行测试一下效果。
最后那个隐藏字段是用来在servlet中做判断的,是支付还是支付成功后的返回,下面在sevlet中会说明。

2.2 Servlet处理请求

servlet主要处理与易宝的相关请求,里面有两个部分的内容,一部分是向易宝发送明文和密文,另一部分是判断易宝发过来的明文和密文,我们看看demo中具体的实现代码:

public class PayServlet extends HttpServlet {
  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    String status = request.getParameter("status");
    if (status.equals("pay")) { //index.jsp中隐藏字段传来的是pay,所以处理支付这部分
      // 加密的密钥,用在加密算法中,由支付中介提供,每个商家独一无二的
      String keyValue = "w0P75wMZ203fr46r5i70V556WHFa94j14yW5J6vuh4yo3nRl5jsqF3c41677";
      // 1: 给参数赋值,这些参数(即明文)都是易宝官方提供的文档中所定义的,名字我们不能改
      String p0_Cmd = formatString("Buy");
      String p1_MerId = formatString("10000940764");
      String p2_Order = formatString(request.getParameter("p2_Order"));
      String p3_Amt = formatString(request.getParameter("p3_Amt"));
      String p4_Cur = formatString("CNY");
      String p5_Pid = "";
      String p6_Pcat = "";
      String p7_Pdesc = "";
      String p8_Url = "http://www.tongji.edu.cn";//这是支付成功后跳转到的页面,可以设为商城首页,这个demo就用同济大学主页好了……
      String p9_SAF = "0";
      String pa_MP = "";
      String pd_FrpId = formatString(request.getParameter("pd_FrpId"));
      pd_FrpId = pd_FrpId.toUpperCase();
      String pr_NeedResponse = "0";

      String hmac = formatString("");//hmac是用来存储密文的
      /*上面所有的明文都用都用formatString方法包装了一下,该方法在下面,主要是将null转换成""
       *因为null是无法转换成密文的*/

      // 解决数据安全性问题: 把明文加密--->密文  然后把明文和密文都交给易宝
      // 易宝拿到数据后,把传过来的明文加密, 和传过来密文比较,
      // 如果相等数据没有被篡改 (商家与易宝加密时都用的是相同key)

      // 把明文数据追加到StringBuffer,注意追加顺序不能改,否则生成的密文会不同的,
      // 要严格按照易宝的官方文档说名来写才行,因为易宝那边就是根据文档中的顺序追加的
      StringBuffer infoBuffer = new StringBuffer();
      infoBuffer.append(p0_Cmd);
      infoBuffer.append(p1_MerId);
      infoBuffer.append(p2_Order);
      infoBuffer.append(p3_Amt);
      infoBuffer.append(p4_Cur);
      infoBuffer.append(p5_Pid);
      infoBuffer.append(p6_Pcat);
      infoBuffer.append(p7_Pdesc);
      infoBuffer.append(p8_Url);
      infoBuffer.append(p9_SAF);
      infoBuffer.append(pa_MP);
      infoBuffer.append(pd_FrpId);
      infoBuffer.append(pr_NeedResponse);
      // 加密后的密文存储到了hmac中,加密算法易宝会提供的,因为他那边也得用相同的算法
      hmac = DigestUtil.hmacSign(infoBuffer.toString(), keyValue);
      // 把明文和密文都存储到request.setAttribute中
      request.setAttribute("p0_Cmd", p0_Cmd);
      request.setAttribute("p1_MerId", p1_MerId);
      request.setAttribute("p2_Order", p2_Order);
      request.setAttribute("p3_Amt", p3_Amt);
      request.setAttribute("p4_Cur", p4_Cur);
      request.setAttribute("p5_Pid", p5_Pid);
      request.setAttribute("p6_Pcat", p6_Pcat);
      request.setAttribute("p7_Pdesc", p7_Pdesc);
      request.setAttribute("p8_Url", p8_Url);
      request.setAttribute("p9_SAF", p9_SAF);
      request.setAttribute("pa_MP", pa_MP);
      request.setAttribute("pd_FrpId", pd_FrpId);
      request.setAttribute("pr_NeedResponse", pr_NeedResponse);
      request.setAttribute("hmac", hmac);
      System.out.println("hmac-->" + hmac);
      //跳转到reqpay.jsp中,将这些信息提交到易宝
      request.getRequestDispatcher("/reqpay.jsp").forward(request,
          response);
    } else if (status.equals("success")) {//易宝那边传来的是success,处理返回验证部分
      PrintWriter out = response.getWriter();
      String keyValue = "w0P75wMZ203fr46r5i70V556WHFa94j14yW5J6vuh4yo3nRl5jsqF3c41677";
      // 获取所有的明文
      String r0_Cmd = formatString(request.getParameter("r0_Cmd"));
      String p1_MerId = request.getParameter("p1_MerId");
      String r1_Code = formatString(request.getParameter("r1_Code"));
      String r2_TrxId = formatString(request.getParameter("r2_TrxId"));
      String r3_Amt = formatString(request.getParameter("r3_Amt"));
      String r4_Cur = formatString(request.getParameter("r4_Cur"));
      String r5_Pid = new String(formatString(
          request.getParameter("r5_Pid")).getBytes("iso-8859-1"),
          "UTF-8");
      String r6_Order = formatString(request.getParameter("r6_Order"));
      String r7_Uid = formatString(request.getParameter("r7_Uid"));
      String r8_MP = new String(formatString(
          request.getParameter("r8_MP")).getBytes("iso-8859-1"),
          "UTF-8");
      String r9_BType = formatString(request.getParameter("r9_BType"));
      // 对明文进行数据追加
      String hmac = formatString(request.getParameter("hmac"));
      StringBuffer infoBuffer = new StringBuffer();
      infoBuffer.append(p1_MerId);
      infoBuffer.append(r0_Cmd);
      infoBuffer.append(r1_Code);
      infoBuffer.append(r2_TrxId);
      infoBuffer.append(r3_Amt);
      infoBuffer.append(r4_Cur);
      infoBuffer.append(r5_Pid);
      infoBuffer.append(r6_Order);
      infoBuffer.append(r7_Uid);
      infoBuffer.append(r8_MP);
      infoBuffer.append(r9_BType);
      // 对返回的明文进行加密
      String md5 = DigestUtil.hmacSign(infoBuffer.toString(), keyValue);
      // 判断加密的密文与传过来的数据签名是否相等
      boolean isOK = md5.equals(hmac);
      if (isOK && r1_Code.equals("1")) {//r1_Code为1表示成功
        //把支付成功的订单状态改成已支付,并个给用户显示支付成功信息
        //调用邮件服务接口,短信发送服务等
        //这里就打印一句话呗~
        out.println("订单编号为:" + r6_Order + "支付金额为:" + r3_Amt);

      } else {
        out.println("fail !!!!");
      }
    }
  }

  public void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

    doGet(request, response);
  }

  String formatString(String text) {
    if (text == null) {
      return "";
    }
    return text;
  }
}

2.3 加密算法

明文转密文所用到的加密算法由易宝提供,我们只需要用它将明文转为密文即可,算法如下:

public class DigestUtil {

  private static String encodingCharset = "UTF-8";

  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();
  }

  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) {
    // 参数1: 明文(要加密的数据) 参数2: 密钥
    System.out.println(DigestUtil.hmacSign("11111", "abc"));
    System.out.println(DigestUtil.hmacSign("11111", "abd"));
  // 解决数据安全性问题: 把明文加密--->密文  然后把明文和密文都交给易宝
  // 易宝拿到数据后,把传过来的明文加密, 和传过来密文比较,如果相等数据没有被篡改 (商家与易宝加密时都用的是相同key)
  }
}

加密算法也不去过多的研究了,好像是md5二代加密算法,反正把明文扔进去,肯定加密成密文就行了。下面再看一下reqpay.jsp页面:

<%@page language="java" contentType="text/html;charset=gbk"%>
<html>
  <head>
    <title>To YeePay Page
    </title>
  </head>
  <body>
    <form name="yeepay" action='https://www.yeepay.com/app-merchant-proxy/node' method='POST' target="_blank">
      <input type='hidden' name='p0_Cmd'  value='${requestScope.p0_Cmd}'>
      <input type='hidden' name='p1_MerId' value='${requestScope.p1_MerId}'>
      <input type='hidden' name='p2_Order' value='${requestScope.p2_Order}'>
      <input type='hidden' name='p3_Amt'  value='${requestScope.p3_Amt}'>
      <input type='hidden' name='p4_Cur'  value='${requestScope.p4_Cur}'>
      <input type='hidden' name='p5_Pid'  value='${requestScope.p5_Pid}'>
      <input type='hidden' name='p6_Pcat' value='${requestScope.p6_Pcat}'>
      <input type='hidden' name='p7_Pdesc' value='${requestScope.p7_Pdesc}'>
      <input type='hidden' name='p8_Url'  value='${requestScope.p8_Url}'>
      <input type='hidden' name='p9_SAF'  value='${requestScope.p9_SAF}'>
      <input type='hidden' name='pa_MP'  value='${requestScope.pa_MP}'>
      <input type='hidden' name='pd_FrpId' value='${requestScope.pd_FrpId}'>
      <input type="hidden" name="pr_NeedResponse" value="${requestScope.pr_NeedResponse}">
      <input type='hidden' name='hmac' value='${requestScope.hmac}'>
      <input type='submit' />
    </form>
  </body>
</html>

其实该页面很简单,就是将明文和密文一起通过<form>表单传到易宝,易宝的接收url为https://www.yeepay.com/app-merchant-proxy/node,这也是易宝官方提供的,我们写成这个就可以了。其实就一个submit按钮,点击submit按钮就能将明文和密文提交过去了。我们看一下测试结果:

3. 测试支付结果

  简陋的测试前台index.jsp~~~:

     

提交后会到reqpay,jsp,点击提交按钮后的效果如下,我们将工行和建行都测一下:


  

支付流程都没啥问题,本来准备去工行交个1分钱看一下支付完成后的结果,结果发现U盾过期了,因为现在用支付宝比较方便嘛……就没去更新U盾了,但是我开通过工行的e支付,所以上面那个界面中也可以使用e支付,于是我就很大方的付了1分钱~~结果如下:


  

然后会跳转到我们之前指定的页面,也就是同济大学咯……好了,测试完成了,整个支付流程结束!
这一节主要是通过一个简单的demo测试一下,看能否和银行的支付界面接上,现在测试是没问题的,已经接上了,后面只要照常支付即可。简单的demo就介绍到这吧,后面就真正继续我们之前的网上商城项目的在线支付模块的开发了。

原文地址:http://blog.csdn.net/eson_15/article/details/51447492

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • php 网上商城促销设计实例代码

    大体的思想,每一个促销要新建一个促销类,有专门的开关来控制是否生效. 用商品里面的促销识别码来判断具体调用哪一个促销实例. 首先,在添加商品的时候,分两步,第一步是添加状态,第二步是把购物车内的商品显示这个状态. 一,添加步骤几个重要的点: 1,添加商品之前,遍历所有的促销互斥条件. 例如,某一款商品不可以和另一个商品同时在一个购物车内:或者某个用户权限,不可以购买特定的一件商品等等. 2,添加商品之前,选择特定的促销实例,来进行添加之前的操作. 注:第二点与第一点的区别在于1是要遍历所有的促销

  • php网上商城购物车设计代码分享

    首先,购物车的数据库设计: 1. id 2. goods_id 商品ID 3. session_id 购物车ID 4. goods_sn 商品编码 5. goods_name 商品名称 6. shop_price 商品商城售价 7. goods_price 商品真实售价(与shop_price的区别在于,当打折的时候,shop_price是打折之前商品的售价,而goods_price是打折之后的) 8. goods_number 数量 9. weight 商品重量 10. goods_attr

  • SSH框架网上商城项目第20战之在线支付平台

    之前已经完成了首页的显示,用户添加购物车,确认订单等功能,下面就是支付功能的开发了.用户确认了订单后会直接跳转到支付页面进行在线支付,在线支付需要第三方的接口,这一节主要介绍一些关于第三方支付的内容,从下一节开始,我们真正开发在线支付模块. 1. 在线支付介绍 在线支付是指卖方与买方通过因特网上的电子商务网站进行交易时,银行为其提供网上资金结算服务的一种业务.它为企业和个人提供了一个安全.快捷.方便的电子商务应用环境和网上资金结算工具.在线支付不仅帮助企业实现了销售款项的快速归集,缩短收款周期,

  • SSH框架网上商城项目第1战之整合Struts2、Hibernate4.3和Spring4.2

    本文开始做一个网上商城的项目,首先从搭建环境开始,一步步整合S2SH.这篇博文主要总结一下如何整合Struts2.Hibernate4.3和Spring4.2. 整合三大框架得先从搭建各部分环境开始,也就是说首先得把Spring,Hibernate和Struts2的环境搭建好,确保它们没有问题了,再做整合.这篇博文遵从的顺序是:先搭建Spring环境-->然后搭建Hibernate环境--> 整合Spring和Hibernate --> 搭建Struts2环境 --> 整合Spri

  • SSH+Jquery+Ajax框架整合

    近期学习了SSH2(Struts2+Spring+Hibernate)的整合后,开始尝试的写一个登陆界面,结果发现:若是单单使用struts2来进行页面跳转的话页面的效果不怎么样,同时也无法进行局部刷新(即异步提交验证). 于是,我开始在网上搜索解决的办法,有些说通过一个隐藏的iframe来达到效果,当我总觉得麻烦和不实用.后来问了下老师,告诉了我使用ajax可以达到想要的效果,我又发现网上有很多例子都是ajax的,但缺少的就是SSH2(整合好的)和ajax 的整合(ajax使用了jQuery框

  • SSH框架网上商城项目第22战之银行图标以及支付页面显示

    从上一节的小demo中我们搞清楚了如何跟易宝对接以及易宝的支付流程.这一节我们来做一下支付页面以及在页面中导入银行图标. 1. 存储银行图标 银行图标一般不会总是去加载,因为这些东西是死的,没必要每次进入支付页面就去加载银行图标,这样性能会受到一定的影响.这让我们联想到了之前的加载首页数据了,其实跟那个道理是一样的,我们可以在项目启动的时候就将银行图标资源加载到application中,后面用到了就直接在application域中取就行了.所以跟原来一样,我们在监听器中加载银行图标. 银行图标易

  • SSH框架的常见问题和解决方法

    Hibernate工作原理及为什么要用? 原理: 1.读取并解析配置文件 2.读取并解析映射信息,创建SessionFactory 3.打开Sesssion 4.创建事务Transation 5.持久化操作 6.提交事务 7.关闭Session 8.关闭SesstionFactory 为什么要用: 1. 对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码. 2. Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现.他很大程度的简化DAO层的编码工作

  • Java的web开发中SSH框架的协作处理应用笔记

    相信SSH没人不知道了吧,struts2+spring+hibernate,企业开发的"基础"架构,为什么基础标上引号,因为这个基础只是很多人自以为的而已,最基础的是servlet,很多培训机构很多基础都不教,直接上来就三大框架了,SSH不然就SSI,搞得很多人以为JAVAWEB开发就一定要框架,没框架就跟没了手一个样.三大框架没有什么坏处,实用,很多公司都在用,直接上手开发.但毕业以为真的好久没用三大框架了,spring倒是有用,特别是springMVC,感觉用起来比struts2爽

  • SSH框架网上商城项目第4战之EasyUI菜单的实现

    上篇文章我们使用EasyUI搭建了后台页面的框架,点击这里查看,这一节我们主要使用EasyUI技术简单实现后台菜单,先将简单功能做出来,后期再继续丰富. 1. 实现左侧菜单 首先看一下效果图: 我们可以点击"基本操作"和"其他操作"来切换菜单选项,在具体的选项内,点击不同的连接,会在右侧显示出来.我们先把左边的菜单做出来. 左侧菜单内容主要有两个:"类别管理"和"商品管理".我们知道,上一节中,在aindex.jsp中应将后台

  • java网上商城开发之邮件发送功能(全)

    最近在学习网上商城时,接触到了一个邮件发送的功能.之前一直在使用邮箱进行发送邮件,但是其中的具体如何运转的却不知道是怎么回事.那么邮件发送究竟是怎么一回事呢? 邮件发送过程: 过程描述:首先是发送人将邮件通过客户端软件发送到特定的服务器上,然后通过电子邮件简单传输协议(SMTP)来进行传输,收件人通过POP3协议将邮件从服务器上接受回来.这样就实现了邮件之间的相互传送. 实现过程: 在有网络的情况下,我们可以直接使用搜狐.网易等邮箱进行发送.那么如何在没有网络的情况下,实现内部之间的发送呢? 首

随机推荐