在线支付功能

来源:互联网 发布:世界上首例网络攻击 编辑:程序博客网 时间:2024/05/16 19:40

             不得不说今天做出了在线支付,从内而外的好开森呐,真的是在线支付啊,还花了我一分钱呢,刚开始我还有点不相信

一、在线支付方式:分为两种,并且他们都各自有优缺点

       第一种方式:网站与各个银行的网银进行对接



第二种支付方式:网站先与第三方支付公司进行对接,第三方支付公司再与各个银行的网银系统进行对接


二、在线支付的流程分析(这里用到的是与第三方支付公司易宝对接)

       网站重定向到第三方支付公司,再重定向跳转到网银系统,在网银中付款完成再次重定向到第三方支付公司,然后通知你的网站支付成功,回到你的网站。期间各种重定向需要传递很多数据信息,如何保证数据安全,这里就有了电子签名(账号,加密算法,秘钥)。


        第三方支付产品接口文档是很关键的:1.支付请求参数说明,需要向易宝提交的数据;2.支付结果参数说明,网银支付成功之后,第三方支付公司带回网站的信息

三、业务分析

        订单付款的功能:

        * 在线支付的方式:

              *与第三方支付公司对接:(易宝)

              *在线支付的流程:

        *付款功能代码实现:

              *修改订单数据:(收货人,地址,电话)

              *完成付款的功能

四、代码实现

        order.jsp页面传递一些网站页面的信息,如收货人,地址电话,然后转到要执行action的方法

<%@ 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"/></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="user.addr" type="text" value="<s:property value="model.user.addr"/>" style="width:350px" /><br />收货人   :<input name="order.user.username" type="text" value="<s:property value="model.user.name"/>" style="width:150px" /><br /> 联系方式:<input name="order.user.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>

        OrderAction类中接收支付通道编码,也就是选择哪个银行;为订单付款包括修改订单(传入收货人,地址,电话)到数据库。为订单付款(调用第三方公司的接口,传入所需要的参数)。付款成功后的转向:修改订单状态为已经付款。在页面显示付款成功信息。交易结果返回类型r9_BType有两种:为“1”:浏览器重定向(浏览器重定向到第三方再重定向到网站),为“2”:服务器点对点通讯(网银通知第三方支付公司,收到钱以后,向固定ip地址的网站上输出“2”)

package cn.itcast.shop.order.action;import java.io.IOException;import java.util.Date;import org.apache.struts2.ServletActionContext;import cn.itcast.shop.cart.vo.Cart;import cn.itcast.shop.cart.vo.CartItem;import cn.itcast.shop.order.service.OrderService;import cn.itcast.shop.order.vo.Order;import cn.itcast.shop.order.vo.OrderItem;import cn.itcast.shop.user.vo.User;import cn.itcast.shop.utils.PageBean;import cn.itcast.shop.utils.PaymentUtil;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionSupport;import com.opensymphony.xwork2.ModelDriven;/* * 订单管理的Action * @author 马晓璐 */public class OrderAction extends ActionSupport implements ModelDriven<Order>{//模型驱动使用的对象private Order order=new Order();//注入OrderServiceprivate OrderService orderService;//接收page参数private Integer page;//接收支付通道编码:private String pd_FrpId;//接收付款成功后的响应数据:private String r6_Order;private String r3_Amt;public void setR6_Order(String r6_Order) {this.r6_Order = r6_Order;}public void setR3_Amt(String r3_Amt) {this.r3_Amt = r3_Amt;}public void setPd_FrpId(String pd_FrpId) {this.pd_FrpId = pd_FrpId;}public void setPage(Integer page) {this.page = page;}public Order getModel(){return order;}public void setOrderService(OrderService orderService) {this.orderService = orderService;}//生成订单的方法:public String save(){//1.保存数据到数据库//订单数据补全:order.setOrdertime(new Date());order.setState(1);  //1.未付款   2. 已经付款,但是没有发货    3.已经发货,但是没有确认收货    4.交易完成 //总计的数据是购物车中的信息:Cart cart = (Cart) ServletActionContext.getRequest().getSession().getAttribute("cart");if(cart==null){this.addActionError("亲,您还没有购物,请先去购物!");return "msg";}order.setTotal(cart.getTotal());// 设置订单项集合:for (CartItem cartItem : cart.getCartItems()) {// 订单项的信息从购物项获得的.OrderItem orderItem = new OrderItem();orderItem.setCount(cartItem.getCount());orderItem.setSubtotal(cartItem.getSubtotal());orderItem.setProduct(cartItem.getProduct());orderItem.setOrder(order);order.getOrderItems().add(orderItem);}// 设置订单关联的客户:User existUser = (User) ServletActionContext.getRequest().getSession().getAttribute("existUser");if (existUser == null) {this.addActionMessage("亲!您还没有登录!");return "login";}order.setUser(existUser);orderService.save(order);//2.将订单对象显示到页面上://通过值栈的形式//清空购物车cart.clearCart();return "saveSuccess";}//我的订单的查询public String findByUid(){//根据用户的id查询User user=(User) ServletActionContext.getRequest().getSession().getAttribute("existUser");//调用ServicePageBean<Order> pageBean=orderService.findByUid(user.getUid(),page);//将分页数据显示到页面上ActionContext.getContext().getValueStack().set("pageBean",pageBean);return "findByUidSuccess";}// 根据订单id查询订单:public String findByOid() {order = orderService.findByOid(order.getOid());return "findByOidSuccess";}//为订单付款的方法public String payOrder() throws IOException{//修改订单Order currOrder=orderService.findByOid(order.getOid());currOrder.setAddr(order.getAddr());currOrder.setName(order.getName());currOrder.setPhone(order.getPhone()); orderService.update(currOrder);//为订单付款String p0_Cmd="Buy";  //业务类型String p1_MerId="10001126856";  //商户编号String p2_Order=order.getOid().toString();  //订单编号String p3_Amt="0.01";  //付款金额String p4_Cur="CNY";  //交易币种String p5_Pid="";  //商品名称String p6_Pcat="";  //商品种类String p7_Pdesc="";  //商品描述String p8_Url="http://localhost:8080/shop/order_callBack.action";  //支付成功后跳转的页面String p9_SAF="";  //送货地址String pa_MP="";  //扩展信息String pd_FrpId=this.pd_FrpId;  //支付通道编码String pr_NeedResponse="1";  //应答机制String keyValue = "69cl522AV6q613Ii4W6u8K6XuW8vM1N6bFgyv769220IuYe9u37N4y7rI4Pl"; // 秘钥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);  // hmac// 向易宝发送请求:StringBuffer sb = new StringBuffer("https://www.yeepay.com/app-merchant-proxy/node?");sb.append("p0_Cmd=").append(p0_Cmd).append("&");sb.append("p1_MerId=").append(p1_MerId).append("&");sb.append("p2_Order=").append(p2_Order).append("&");sb.append("p3_Amt=").append(p3_Amt).append("&");sb.append("p4_Cur=").append(p4_Cur).append("&");sb.append("p5_Pid=").append(p5_Pid).append("&");sb.append("p6_Pcat=").append(p6_Pcat).append("&");sb.append("p7_Pdesc=").append(p7_Pdesc).append("&");sb.append("p8_Url=").append(p8_Url).append("&");sb.append("p9_SAF=").append(p9_SAF).append("&");sb.append("pa_MP=").append(pa_MP).append("&");sb.append("pd_FrpId=").append(pd_FrpId).append("&");sb.append("pr_NeedResponse=").append(pr_NeedResponse).append("&");sb.append("hmac=").append(hmac);// 重定向:向易宝出发:ServletActionContext.getResponse().sendRedirect(sb.toString());    return NONE;}//付款成功后的转向public String callBack(){//修改订单状态:修改状态为已经付款Order currOrder=orderService.findByOid(Integer.parseInt(r6_Order));currOrder.setState(2);orderService.update(currOrder);//在页面显示付款成功信息!this.addActionMessage("订单付款成功:订单编号:"+r6_Order+"付款的金额:"+r3_Amt);return "msg";}         } 

Service业务层的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 马晓璐 */@Transactionalpublic class OrderService {private OrderDao orderDao;public void setOrderDao(OrderDao orderDao) {this.orderDao = orderDao;}//保存订单的业务层代码public void save(Order order) {orderDao.save(order);}// 业务层根据用户id查询订单,带分页查询.public PageBean<Order> findByUid(Integer uid,Integer page) {PageBean<Order> pageBean = new PageBean<Order>();// 设置当前页数:pageBean.setPage(page);// 设置每页显示记录数:// 显示5个int limit = 5;pageBean.setLimit(limit);// 设置总记录数:int totalCount = 0;totalCount = orderDao.findCountByUid(uid);pageBean.setTotalCount(totalCount);// 设置总页数int totalPage = 0;if(totalCount % limit == 0){totalPage = totalCount / limit;}else{totalPage = totalCount / limit + 1;}pageBean.setTotalPage(totalPage);// 设置每页显示数据集合:int begin = (page - 1)*limit;List<Order> list = orderDao.findPageByUid(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);}}

Dao层的OrderDao类

package cn.itcast.shop.order.dao;import java.util.Date;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 {//dao层的保存订单的方法public void save(Order order) {this.getHibernateTemplate().save(order);}// Dao层查询我的订单分页查询:统计个数public Integer findCountByUid(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> findPageByUid(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;}// DAO层根据订单id查询订单public Order findByOid(Integer oid) {return this.getHibernateTemplate().get(Order.class, oid);}//DAO层的修改订单的操作public void update(Order currOrder) {this.getHibernateTemplate().update(currOrder);}}

算法工具类PaymentUtil

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);// 易宝支付会员IDsValue.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"));//}}

vo层的Order.java

package cn.itcast.shop.order.vo;import java.util.Date;import java.util.HashSet;import java.util.Set;import cn.itcast.shop.user.vo.User;public class Order {private Integer oid;private Double total;private Date ordertime;private Integer state;// 1:未付款   2:订单已经付款   3:已经发货   4:订单结束private String name;private String phone;private String addr;// 用户的外键:对象private User user;// 配置订单项的集合private Set<OrderItem> orderItems = new HashSet<OrderItem>();public Integer getOid() {return oid;}public void setOid(Integer oid) {this.oid = oid;}public Double getTotal() {return total;}public void setTotal(Double total) {this.total = total;}public Date getOrdertime() {return ordertime;}public void setOrdertime(Date ordertime) {this.ordertime = ordertime;}public Integer getState() {return state;}public void setState(Integer state) {this.state = state;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}public String getAddr() {return addr;}public void setAddr(String addr) {this.addr = addr;}public User getUser() {return user;}public void setUser(User user) {this.user = user;}public Set<OrderItem> getOrderItems() {return orderItems;}public void setOrderItems(Set<OrderItem> orderItems) {this.orderItems = orderItems;}}

小结:在线支付功能在以后做电商类的项目中是肯定少不了的,调用第三方确实方便了好多,只需要调用第三方接口按照第三方文档传入对应的参数即可,算法工具类的一些加密算法是少不了的,数据传输过程中的安全问题才是最重要的,数据重定向返回时的一些判断这里没有写,以后一定要注意一些判断和支付安全问题。



0 0