在线支付是指卖方与卖方通过因特网上的电子商务网站进行交易时,银行为其提供网上资金结算服务的一种业务,她为企业和个人提供了一个安全、快捷、方便的电子商务应用环境和网上资金结算工具,在线支付不仅帮助企业实现了销售款项的快速归集,缩短收款周期,同时也为个人网上银行客户提供了网上消费支付结算方式,使客户正在做到了足不出户,网上购物,不知道小伙伴们有没有这种感觉,逛街的时候,还能管住自己,少买点,因为钞票是直接通过自己的手给了卖家,但是网购就不一样了,我们直接点击鼠标,一个按钮的操作,钞票就嗖的一下打到第三方支付公司了,但是并没有啥感觉,还想买,因为没有经过自己的手,没有那么心疼,咳咳,以前的时候感觉支付特别的神秘,随着项目的进行,在小便的项目中也遇到这个功能,在线支付,今天这篇博客,小编就来简单的和小伙伴的分享一下如何使用SSH框架实现在线支付功能,希望对有需要的小伙伴有帮助,还请小伙伴们多多指教。
要想完成在线支付的功能,首先我们来简单的来了解一下在线支付的方式,在线支付方式有两种,第一种支付方式,就是通过网站和各个银行直接进行对接,从而完成支付操作;第二种方式,网站通过和第三方公司进行对接,第三方公司再和各个银行进行对接,完成支付操作,那么两种支付方式有什么优点和缺点呢?如下所示:
第一种支付方式:(网站直接和各个银行进行对接);
优点:免费;
缺点:网站需要了解各个银行的网银系统,才可以完成对接;
第二种方式:(网站和第三方支付公司对接,第三方公司再和网站进行对接);
优点:网站不需要了解各个网银的接口,了解第三方支付公司的接口;
缺点:收费的,一般费用1%,安全,使用方便,支付担保业务可以在很大程度上保证付款人的收益。介绍完了支付的方式,接着结合小编的项目来分析一下在线支付的流程,在小编的项目中采用第二种支付方式,也就是网站和第三方公司对接,第三方公司再和网站进行对接;那么这中方式的流程是什么样子呢?用户访问网站,找到第三方支付公司,那么用户如何才能找到第三方公司呢?通过重定向,才能找到第三方公司,有的小伙伴可能会说,使用转发的方法,转发市过不去的,因为转发只能实现内容的跳转;第三方公司进行付款的操作,肯定要跳转到网银的界面,那么怎么样才能跳转到网银的界面呢?没错还是需要通过重定向的操作,这个时候会重定向到网银系统,网银中进行付款的操作,这个时候需要重定向到第三方支付公司,这个时候,又回到第三方支付公司,第三方支付公司付完款之后通知网站,支付成功,这个过程中都是一系列的重定向操作,这一个过程,会传递很多的数据,那么如何保证数据的安全呢?这个时候,我们需要用到电子签名,所谓的电子签名,就是指数据电文中以电子形式所含、所附用于识别签名人身份并表明签名人认可其中内容的数据。通俗点说,电子签名就是通过密码技术对电子文档的电子形式的签名,并非是书面签名的数字图像化,它类似于手写签名或印章,也可以说它就是电子印章。接着,小编画一张图来简简单的说明一下,在线支付的流程,如下图所示:
ok,接着小编来详细讲解一下,如何使用SSH框架完成支付的功能,首先第一步,我们来编写jsp里面的代码,如下所示:
+<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri ="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- saved from url=(0043)http://localhost:8080/mango/cart/list.jhtml -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>订单页面</title>
<link href="${pageContext.request.contextPath}/css/common.css" rel="stylesheet" type="text/css"/>
<link href="${pageContext.request.contextPath}/css/cart.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div class="container header">
<div class="span5">
<div class="logo">
<a href="./网上商城/index.htm">
<img src="${pageContext.request.contextPath}/image/r___________renleipic_01/logo.gif" alt="传智播客"/>
</a>
</div>
</div>
<div class="span9">
<div class="headerAd">
<img src="${pageContext.request.contextPath}/image/header.jpg" width="320" height="50" alt="正品保障" title="正品保障"/>
</div>
</div>
<%@ include file="menu.jsp" %>
</div>
<div class="container cart">
<div class="span24">
<div class="step step1">
<ul>
<li class="current"></li>
<li >生成订单成功</li>
</ul>
</div>
<table>
<tbody>
<tr>
<th colspan="5">订单编号:<s:property value="model.oid"/></th>
</tr>
<tr>
<th>图片</th>
<th>商品</th>
<th>价格</th>
<th>数量</th>
<th>小计</th>
</tr>
<s:iterator var="orderItem" value="model.orderItems">
<tr>
<td width="60">
<input type="hidden" name="id" value="22"/>
<img src="${ pageContext.request.contextPath }/<s:property value="#orderItem.product.image"/>"/>
</td>
<td>
<a target="_blank"><s:property value="#orderItem.product.pname"/></a>
</td>
<td>
<s:property value="#orderItem.product.shop_price"/>
</td>
<td class="quantity" width="60">
<s:property value="#orderItem.count"/>
<input type="text" name="count" value="1" maxlength="4" onpaste="return false;"/>
</td>
<td width="140">
<span class="subtotal">¥<s:property value="#orderItem.subtotal"/></span>
</td>
</tr>
</s:iterator>
</tbody>
</table>
<dl id="giftItems" class="hidden" style="display: none;">
</dl>
<div class="total">
<em id="promotion"></em>
商品金额: <strong id="effectivePrice">¥<s:property value="model.total"/>元</strong>
</div>
<form id="orderForm" action="${pageContext.request.contextPath }/order_payOrder.action" method="post">
<input type="hidden" name="oid" value="<s:property value="model.oid"/>"/>
<div class="span24">
<p>
收货地址:<input name="addr" type="text" value="<s:property value="model.user.addr"/>" style="width:350px" />
<br />
收货人 :<input name="name" type="text" value="<s:property value="model.user.name"/>" style="width:150px" />
<br />
联系方式:<input name="phone" type="text"value="<s:property value="model.user.phone"/>" style="width:150px" />
</p>
<hr />
<p>
选择银行:<br/>
<input type="radio" name="pd_FrpId" value="ICBC-NET-B2C" checked="checked"/>工商银行
<img src="${ pageContext.request.contextPath }/bank_img/icbc.bmp" align="middle"/>
<input type="radio" name="pd_FrpId" value="BOC-NET-B2C"/>中国银行
<img src="${ pageContext.request.contextPath }/bank_img/bc.bmp" align="middle"/>
<input type="radio" name="pd_FrpId" value="ABC-NET-B2C"/>农业银行
<img src="${ pageContext.request.contextPath }/bank_img/abc.bmp" align="middle"/>
<br/>
<input type="radio" name="pd_FrpId" value="BOCO-NET-B2C"/>交通银行
<img src="${ pageContext.request.contextPath }/bank_img/bcc.bmp" align="middle"/>
<input type="radio" name="pd_FrpId" value="PINGANBANK-NET"/>平安银行
<img src="${ pageContext.request.contextPath }/bank_img/pingan.bmp" align="middle"/>
<input type="radio" name="pd_FrpId" value="CCB-NET-B2C"/>建设银行
<img src="${ pageContext.request.contextPath }/bank_img/ccb.bmp" align="middle"/>
<br/>
<input type="radio" name="pd_FrpId" value="CEB-NET-B2C"/>光大银行
<img src="${ pageContext.request.contextPath }/bank_img/guangda.bmp" align="middle"/>
<input type="radio" name="pd_FrpId" value="CMBCHINA-NET-B2C"/>招商银行
<img src="${ pageContext.request.contextPath }/bank_img/cmb.bmp" align="middle"/>
</p>
<hr />
<p style="text-align:right">
<a href="javascript:document.getElementById('orderForm').submit();">
<img src="${pageContext.request.contextPath}/images/finalbutton.gif" width="204" height="51" border="0" />
</a>
</p>
</div>
</form>
</div>
</div>
<div class="container footer">
<div class="span24">
<div class="footerAd">
<img src="image\r___________renleipic_01/footer.jpg" alt="我们的优势" title="我们的优势" height="52" width="950">
</div>
</div>
<div class="span24">
<ul class="bottomNav">
<li>
<a href="#">关于我们</a>
|
</li>
<li>
<a href="#">联系我们</a>
|
</li>
<li>
<a href="#">诚聘英才</a>
|
</li>
<li>
<a href="#">法律声明</a>
|
</li>
<li>
<a>友情链接</a>
|
</li>
<li>
<a target="_blank">支付方式</a>
|
</li>
<li>
<a target="_blank">配送方式</a>
|
</li>
<li>
<a >SHOP++官网</a>
|
</li>
<li>
<a>SHOP++论坛</a>
</li>
</ul>
</div>
<div class="span24">
<div class="copyright">Copyright © 2005-2015 网上商城 版权所有</div>
</div>
</div>
</body>
</html>
第二步,我们需要接收支付的通道,编码如下所示:
package cn.itcast.shop.cart.action;
import org.apache.struts2.ServletActionContext;
import cn.itcast.shop.cart.vo.Cart;
import cn.itcast.shop.cart.vo.CartItem;
import cn.itcast.shop.product.service.ProductService;
import cn.itcast.shop.product.vo.Product;
import com.opensymphony.xwork2.ActionSupport;
/**
* 购物车Action
*
* @author 丁国华
*
*/
public class CartAction extends ActionSupport {
// 接收pid
private Integer pid;
// 接收数量count
private Integer count;
// 注入商品的Service
private ProductService productService;
public void setProductService(ProductService productService) {
this.productService = productService;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public void setCount(Integer count) {
this.count = count;
}
// 将购物项添加到购物车:执行的方法
public String addCart() {
// 封装一个CartItem对象.
CartItem cartItem = new CartItem();
// 设置数量:
cartItem.setCount(count);
// 根据pid进行查询商品:
Product product = productService.findByPid(pid);
// 设置商品:
cartItem.setProduct(product);
// 将购物项添加到购物车.
// 购物车应该存在session中.
Cart cart = getCart();
cart.addCart(cartItem);
return "addCart";
}
// 清空购物车的执行的方法:
public String clearCart(){
// 获得购物车对象.
Cart cart = getCart();
// 调用购物车中清空方法.
cart.clearCart();
return "clearCart";
}
// 从购物车中移除购物项的方法:
public String removeCart(){
// 获得购物车对象
Cart cart = getCart();
// 调用购物车中移除的方法:
cart.removeCart(pid);
// 返回页面:
return "removeCart";
}
// 我的购物车:执行的方法
public String myCart(){
return "myCart";
}
/**
* 获得购物车的方法:从session中获得购物车.
* @return
*/
private Cart getCart() {
Cart cart = (Cart) ServletActionContext.getRequest().getSession()
.getAttribute("cart");
if (cart == null) {
cart = new Cart();
ServletActionContext.getRequest().getSession()
.setAttribute("cart", cart);
}
return cart;
}
}
第三步,编写orderService里面的代码如下所示:
package cn.itcast.shop.order.service;
import java.util.List;
import org.springframework.transaction.annotation.Transactional;
import cn.itcast.shop.order.dao.OrderDao;
import cn.itcast.shop.order.vo.Order;
import cn.itcast.shop.utils.PageBean;
/**
* 订单模块,业务层代码
* @author丁国华
*
*/
@Transactional
public class OrderService {
private OrderDao orderDao;
public void setOrderDao(OrderDao orderDao) {
this.orderDao = orderDao;
}
//保存订单的业务层代码
public void save(Order order) {
orderDao.save(order);
}
//我的订单业务层的代码
public PageBean<Order> findByPageUid(Integer uid, Integer page) {
PageBean<Order> pageBean = new PageBean<Order>();
//设置当前页数
pageBean.setPage(page);
//设置当前显示的记录数;
Integer limit = 5;
pageBean.setLimit(limit);
//设置总记录数
Integer totalCount = null;
totalCount=orderDao.findByCountUid(uid);
pageBean.setTotalCount(totalCount);
//设置总页数
Integer totalPage = null;
if(totalCount % limit==0){
totalPage = totalCount/limit;
}else{
totalPage = totalCount/limit+1;
}
pageBean.setTotalPage(totalPage);
//设置每页显示数据集合
Integer begin = (page -1) * limit;
List<Order> list = orderDao.findByPageUid(uid,begin,limit);
pageBean.setList(list);
return pageBean;
}
//业务层:根据订单id查询订单
public Order findByOid(Integer oid) {
return orderDao.findByOid(oid);
}
//业务层修改订单的操作
public void update(Order currOrder) {
orderDao.update(currOrder);
}
}
第四步,编写orderDao里面的代码,如下所示:
package cn.itcast.shop.order.dao;
import java.util.List;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import cn.itcast.shop.order.vo.Order;
import cn.itcast.shop.utils.PageHibernateCallback;
/**
* 订单模块Dao层的代码
*
* @author 丁国华
*
*/
public class OrderDao extends HibernateDaoSupport {
//保存订单的业务层代码
public void save(Order order) {
this.getHibernateTemplate().save(order);
}
//DAO层的我的订单的个数的统计
public Integer findByCountUid(Integer uid) {
String hql ="select count(*) from Order o where o.user.uid=? ";
List<Long> list = this.getHibernateTemplate().find(hql,uid);
if(list != null && list.size()>0){
return list.get(0).intValue();
}
return null;
}
//DAO层的我的订单的查询
public List<Order> findByPageUid(Integer uid, Integer begin, Integer limit) {
String hql ="from Order o where o.user.uid=? order by ordertime desc";
List<Order> list=this.getHibernateTemplate().execute(new PageHibernateCallback<Order>(hql,new Object[]{uid},begin,limit));
return list;
}
public Order findByOid(Integer oid) {
return this.getHibernateTemplate().get(Order.class,oid);
}
//DAO层的修改订单的操作
public void update(Order currOrder) {
this.getHibernateTemplate().update(currOrder);
}
}
第五步,获取hmac,由一个算法和密钥来获得,代码如下所示:
package cn.itcast.shop.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));
}
}
接着,我们来运行一下,看一下效果:
由于后面的操作涉及到个人信息,小编就不进行展示了。
小编寄语:该博文,小编主要简单的介绍了如何使用SSH框架实现在线支付的功能,简单的介绍了直线支付的两种支付方式,并且简单分析了在该项目中用到了支付方式,讲解了一下该项目中的支付流程,简单的实现了在线支付的功能,其实很多时候,很多东西并没有我们详细中的那么困难,只要我们从心里征服她,java之路,精彩仍在继续......