SSH架构实现在线支付功能

时间:2022-03-11 00:27:10

在线支付是指卖方与卖方通过因特网上的电子商务网站进行交易时,银行为其提供网上资金结算服务的一种业务,她为企业和个人提供了一个安全、快捷、方便的电子商务应用环境和网上资金结算工具,在线支付不仅帮助企业实现了销售款项的快速归集,缩短收款周期,同时也为个人网上银行客户提供了网上消费支付结算方式,使客户正在做到了足不出户,网上购物,不知道小伙伴们有没有这种感觉,逛街的时候,还能管住自己,少买点,因为钞票是直接通过自己的手给了卖家,但是网购就不一样了,我们直接点击鼠标,一个按钮的操作,钞票就嗖的一下打到第三方支付公司了,但是并没有啥感觉,还想买,因为没有经过自己的手,没有那么心疼,咳咳,以前的时候感觉支付特别的神秘,随着项目的进行,在小便的项目中也遇到这个功能,在线支付,今天这篇博客,小编就来简单的和小伙伴的分享一下如何使用SSH框架实现在线支付功能,希望对有需要的小伙伴有帮助,还请小伙伴们多多指教。

要想完成在线支付的功能,首先我们来简单的来了解一下在线支付的方式,在线支付方式有两种,第一种支付方式,就是通过网站和各个银行直接进行对接,从而完成支付操作;第二种方式,网站通过和第三方公司进行对接,第三方公司再和各个银行进行对接,完成支付操作,那么两种支付方式有什么优点和缺点呢?如下所示:

  第一种支付方式:(网站直接和各个银行进行对接);

  优点:免费;

  缺点:网站需要了解各个银行的网银系统,才可以完成对接;

  第二种方式:(网站和第三方支付公司对接,第三方公司再和网站进行对接);

  优点:网站不需要了解各个网银的接口,了解第三方支付公司的接口;

  缺点:收费的,一般费用1%,安全,使用方便,支付担保业务可以在很大程度上保证付款人的收益。介绍完了支付的方式,接着结合小编的项目来分析一下在线支付的流程,在小编的项目中采用第二种支付方式,也就是网站和第三方公司对接,第三方公司再和网站进行对接;那么这中方式的流程是什么样子呢?用户访问网站,找到第三方支付公司,那么用户如何才能找到第三方公司呢?通过重定向,才能找到第三方公司,有的小伙伴可能会说,使用转发的方法,转发市过不去的,因为转发只能实现内容的跳转;第三方公司进行付款的操作,肯定要跳转到网银的界面,那么怎么样才能跳转到网银的界面呢?没错还是需要通过重定向的操作,这个时候会重定向到网银系统,网银中进行付款的操作,这个时候需要重定向到第三方支付公司,这个时候,又回到第三方支付公司,第三方支付公司付完款之后通知网站,支付成功,这个过程中都是一系列的重定向操作,这一个过程,会传递很多的数据,那么如何保证数据的安全呢?这个时候,我们需要用到电子签名,所谓的电子签名,就是指数据电文中以电子形式所含、所附用于识别签名人身份并表明签名人认可其中内容的数据。通俗点说,电子签名就是通过密码技术对电子文档的电子形式的签名,并非是书面签名的数字图像化,它类似于手写签名或印章,也可以说它就是电子印章。接着,小编画一张图来简简单的说明一下,在线支付的流程,如下图所示:

SSH架构实现在线支付功能

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="data: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架构实现在线支付功能
        由于后面的操作涉及到个人信息,小编就不进行展示了。

小编寄语:该博文,小编主要简单的介绍了如何使用SSH框架实现在线支付的功能,简单的介绍了直线支付的两种支付方式,并且简单分析了在该项目中用到了支付方式,讲解了一下该项目中的支付流程,简单的实现了在线支付的功能,其实很多时候,很多东西并没有我们详细中的那么困难,只要我们从心里征服她,java之路,精彩仍在继续......