java版支付宝app支付流程及原理分析

  本实例是基于springmvc框架编写
     一、流程步骤
         1.执行流程
           当手机端app(就是你公司开发的app)在支付页面时,调起服务端(后台第1个创建订单接口)接口,后台把需要调起支付宝支付的参数返回给手机端,手机端拿到
         这些参数后,拉起支付宝支付环境完成支付,完成支付后会调异步通知(第2个接口),此时需要给支付宝返回成功或者失败信息,成功后会调用同步通知(第3个接口)
         返回支付成功页面,完成整个支付流程。
        
         2.支付的配置文件AlipayConfig

 public class AlipayConfig {
// 1.商户appid
public static String APPID = "20170812********"; // 2.私钥 pkcs8格式的
public static String RSA_PRIVATE_KEY =""; // 3.支付宝公钥
public static String ALIPAY_PUBLIC_KEY = ""; // 4.服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String notify_url = "http://www.xxx.com/alipay/notify_url.do"; // 5.页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址
public static String return_url = "http://www.xxx.com/alipay/return_url.do"; // 6.请求网关地址
public static String URL = "https://openapi.alipay.com/gateway.do"; // 7.编码
public static String CHARSET = "UTF-8"; // 8.返回格式
public static String FORMAT = "json"; // 9.加密类型
public static String SIGNTYPE = "RSA2"; }

3.第1个创建订单接口

 

 /**
*@param userId 充值人
*@param tradeMoney 充值money(RMB)
*@throws AlipayApiException ModelAndView
*/
@RequestMapping(value="api/alipay/createOrder",method={RequestMethod.POST,RequestMethod.GET})
@ResponseBody
public Model alipay(
@RequestParam("userId")String userId,
@RequestParam("tradeMoney")String tradeMoney,Model m) throws AlipayApiException{ String orderStr = "";
try { /****** 1.封装你的交易订单开始 *****/ //自己用 此处封装你的订单数据,订单状态可以设置为等待支付 /****** 1.封装你的交易订单结束 *****/ Map<String,String> orderMap = new LinkedHashMap<String,String>(); //订单实体
Map<String,String> bizModel = new LinkedHashMap<String,String>(); //公共实体 /****** 2.商品参数封装开始 *****/ //手机端用
// 商户订单号,商户网站订单系统中唯一订单号,必填
orderMap.put("out_trade_no",trade.getOrderNumber());
// 订单名称,必填
orderMap.put("subject","手机网站支付购买游戏币");
// 付款金额,必填
orderMap.put("total_amount",tradeMoney);
// 商品描述,可空
orderMap.put("body","您购买游戏币"+tradeMoney +"元");
// 超时时间 可空
orderMap.put("timeout_express","30m");
// 销售产品码 必填
orderMap.put("product_code","QUICK_WAP_PAY"); /****** 2.商品参数封装结束 *****/ /******--------------- 3.公共参数封装 开始 ------------------------*****/ //支付宝用
//1.商户appid
bizModel.put("app_id",AlipayConfig.APPID);
//2.请求网关地址
bizModel.put("method",AlipayConfig.URL);
//3.请求格式
bizModel.put("format",AlipayConfig.FORMAT);
//4.回调地址
bizModel.put("return_url",AlipayConfig.return_url);
//5.私钥
bizModel.put("private_key",AlipayConfig.RSA_PRIVATE_KEY);
//6.商家id
bizModel.put("seller_id","2088102170411333");
//7.加密格式
bizModel.put("sign_type",AlipayConfig.SIGNTYPE+""); /******--------------- 3.公共参数封装 结束 ------------------------*****/ //实例化客户端
AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE); //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
AlipayTradeAppPayRequest ali_request = new AlipayTradeAppPayRequest(); //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setPassbackParams(URLEncoder.encode((String)orderMap.get("body").toString()));; //描述信息 添加附加数据
model.setBody(orderMap.get("body")); //商品信息
model.setSubject(orderMap.get("subject")); //商品名称
model.setOutTradeNo(orderMap.get("out_trade_no")); //商户订单号(自动生成)
model.setTimeoutExpress(orderMap.get("timeout_express")); //交易超时时间
model.setTotalAmount(orderMap.get("total_amount")); //支付金额
model.setProductCode(orderMap.get("product_code")); //销售产品码
model.setSellerId("20881021********"); //商家id
ali_request.setBizModel(model);
ali_request.setNotifyUrl(AlipayConfig.notify_url); //回调地址 AlipayTradeAppPayResponse response = client.sdkExecute(ali_request);
orderStr = response.getBody();
System.err.println(orderStr); //就是orderString 可以直接给客户端请求,无需再做处理。 m.addAttribute("result",orderStr);
m.addAttribute("status",0);
m.addAttribute("msg","订单生成成功"); } catch (Exception e) {
m.addAttribute("status",1);
m.addAttribute("msg","订单生成失败");
} return m;
}

4.第2个异步回调接口

   /**
* 支付宝支付成功后.回调该接口
* @param request
* @return
* @throws IOException
*/
@RequestMapping(value="api/alipay/notify_url",method={RequestMethod.POST,RequestMethod.GET})
@ResponseBody
public String notify(HttpServletRequest request,HttpServletResponse response) throws IOException {
Map<String, String> params = new HashMap<String, String>();  
       Map<String, String[]> requestParams = request.getParameterMap();  
       Trade trade =null;
//1.从支付宝回调的request域中取值
Map<String, String[]> requestParams = request.getParameterMap(); for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = iter.next();
String[] values = requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
// 乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
params.put(name, valueStr);
}
//2.封装必须参数
String out_trade_no = request.getParameter("out_trade_no"); // 商户订单号
String orderType = request.getParameter("body"); // 订单内容
String tradeStatus = request.getParameter("trade_status"); //交易状态 //3.签名验证(对支付宝返回的数据验证,确定是支付宝返回的)
boolean signVerified = false;
try {
//3.1调用SDK验证签名
signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE); } catch (AlipayApiException e) {
e.printStackTrace();
}
//4.对验签进行处理
if (signVerified) { //验签通过
if(tradeStatus.equals("TRADE_SUCCESS")) { //只处理支付成功的订单: 修改交易表状态,支付成功
Trade trade = tradeService.selectByOrderNumber(out_trade_no);
trade.setTradeStatus((byte)3); //支付完成
int returnResult = tradeService.updateByPrimaryKeySelective(trade); //更新交易表中状态
if(returnResult>0){
return "success";
}else{
return "fail";
}
}else{
return "fail";
}
} else { //验签不通过
System.err.println("验签失败");
return "fail";
}
}

5.第3个同步通知接口

    /**
* 支付宝支付成功后.通知页面
*@author Zhao
*@date 2017年11月2日
*@param request
*@return
*@throws UnsupportedEncodingException
*/
@RequestMapping(value="api/alipay/return_url",method={RequestMethod.POST,RequestMethod.GET})
@ResponseBody
public Model returnUrl(@RequestParam("id") String id,HttpServletRequest request,Model model) throws UnsupportedEncodingException {
System.err.println("。。。。。。 同步通知 。。。。。。");
System.err.println("。。。。。。 同步通知 。。。。。。");
System.err.println("。。。。。。 同步通知 。。。。。。");
Map returnMap = new HashMap();
try { Trade trade = tradeService.selectByOrderNumber(id);
// 返回值Map
if(trade !=null && trade.getTradeStatus() == 2){
User user = userService.selectByPrimaryKey(trade.gettUserId());
returnMap.put("tradeType", trade.getTradeType()); //支付方式
returnMap.put("phoneNum", user.getPhoneNumber()); //支付帐号
returnMap.put("tradeMoney", trade.getTradeMoney()+""); //订单金额 }else{
model.addAttribute("msg", "查询失败");
model.addAttribute("status", 0);
}
model.addAttribute("returnMap", returnMap);
System.err.println(returnMap);
model.addAttribute("msg", "查询成功");
model.addAttribute("status", 0);
} catch (Exception e) {
model.addAttribute("msg", "查询失败");
model.addAttribute("status", 1);
} return model;
}

Trade类

public class Trade {
private Long id; private String orderNumber; private String tradeNumber; private Byte tradeType; private BigDecimal tradeMoney; private String orderName; private String goodsDescribe; private Byte tradeStatus; private Byte orderType; private Date createTime; private Long tUserId; private Date payTime;
private String bankName;
private String payeeName;
private String payeeAccount;
private Date paymentTime; public Date getPaymentTime() {
return paymentTime;
} public void setPaymentTime(Date paymentTime) {
this.paymentTime = paymentTime;
} public String getBankName() {
return bankName;
} public void setBankName(String bankName) {
this.bankName = bankName;
} public String getPayeeName() {
return payeeName;
} public void setPayeeName(String payeeName) {
this.payeeName = payeeName;
} public String getPayeeAccount() {
return payeeAccount;
} public void setPayeeAccount(String payeeAccount) {
this.payeeAccount = payeeAccount;
} public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public String getOrderNumber() {
return orderNumber;
} public void setOrderNumber(String orderNumber) {
this.orderNumber = orderNumber;
} public String getTradeNumber() {
return tradeNumber;
} public void setTradeNumber(String tradeNumber) {
this.tradeNumber = tradeNumber;
} public Byte getTradeType() {
return tradeType;
} public void setTradeType(Byte tradeType) {
this.tradeType = tradeType;
} public BigDecimal getTradeMoney() {
return tradeMoney;
} public void setTradeMoney(BigDecimal tradeMoney) {
this.tradeMoney = tradeMoney;
} public String getOrderName() {
return orderName;
} public void setOrderName(String orderName) {
this.orderName = orderName;
} public String getGoodsDescribe() {
return goodsDescribe;
} public void setGoodsDescribe(String goodsDescribe) {
this.goodsDescribe = goodsDescribe;
} public Byte getTradeStatus() {
return tradeStatus;
} public void setTradeStatus(Byte tradeStatus) {
this.tradeStatus = tradeStatus;
} public Byte getOrderType() {
return orderType;
} public void setOrderType(Byte orderType) {
this.orderType = orderType;
} public Date getCreateTime() {
return createTime;
} public void setCreateTime(Date createTime) {
this.createTime = createTime;
} public Long gettUserId() {
return tUserId;
} public void settUserId(Long tUserId) {
this.tUserId = tUserId;
} public Date getPayTime() {
return payTime;
} public void setPayTime(Date payTime) {
this.payTime = payTime;
} @Override
public String toString() {
return "Trade [id=" + id + ", orderNumber=" + orderNumber + ", tradeNumber=" + tradeNumber + ", tradeType="
+ tradeType + ", tradeMoney=" + tradeMoney + ", orderName=" + orderName + ", goodsDescribe="
+ goodsDescribe + ", tradeStatus=" + tradeStatus + ", orderType=" + orderType + ", createTime="
+ createTime + ", tUserId=" + tUserId + ", payTime=" + payTime + ", bankName=" + bankName
+ ", payeeName=" + payeeName + ", payeeAccount=" + payeeAccount + ", paymentTime=" + paymentTime + "]";
} }

二、测试

  支付宝在app端支付成功后,要调用异步通知,因些需要访问的url必须是外网可以访问的,在这里推荐一款内网穿透工具natapp,需要用身份证号验证,测试个支付是没问题的

   附:

    1. natapp官网: https://natapp.cn

    2.natapp 1分钟新手图文教程: https://natapp.cn/article/natapp_newbie

三、流程分析:
         1.配置文件AlipayConfig注意事项:
             (1)注意沙箱环境和正式环境的不同:
                商户appid    :
                    沙箱:进入沙箱环境会自动分配
                    正式:商户唯一的标识
                请求网关地址:
                    沙箱:https://openapi.alipaydev.com/gateway.do
                    正式:https://openapi.alipay.com/gateway.do
             (2)公钥和私钥
                 公钥和私钥是自己生成的不要配错,与支付宝的公钥不要混淆了。(详情见:https://docs.open.alipay.com/204/105297)
         2. 本案例只是对支付进行说明,退款等功能可进行举一反三编写。
   3.本人由于能力水平有限.有不到之处请大家多多指教!!!

支付宝app支付java后台流程、原理分析(含nei wang chuan tou)的更多相关文章

  1. 微信app支付java后台流程、原理分析及nei网穿透

    一.流程步骤 本实例是基于springmvc框架编写 1.执行流程           当手机端app(就是你公司开发的app)在支付页面时,调起服务端(后台第1个创建订单接口)接口,后台把需要调起微 ...

  2. 支付宝app支付服务端流程

    支付宝APP支付服务端详解 前面接了微信支付,相比微信支付,支付宝APP支付提供了支付封装类,下面将实现支付宝APP支付.订单查询.支付结果异步通知.APP支付申请参数说明,以及服务端返回APP端发起 ...

  3. 手把手教你完成App支付JAVA后台-支付宝支付JAVA

    接着上一篇博客,我们暂时完成了手机端的部分支付代码,接下来,我们继续写后台的代码. 后台基本需要到以下几个参数,我都将他们写在了properties文件中: 支付宝参数 AliPay.payURL = ...

  4. 微信APP支付-java后台实现

    不说废话,直接上代码 先是工具类(注意签名时要排序): import java.io.BufferedReader; import java.io.ByteArrayInputStream; impo ...

  5. 支付宝APP支付Java回调具体步骤

    /** * 支付宝异步请求通知 * * @param request * @return */@RequestMapping(value = "async", method = R ...

  6. 支付宝APP支付之Java后台生成签名具体步骤

    /** *支付宝支付 * @param orderId 订单编号 * @param actualPay 实际支付金额 * @return */ private String getOrderInfoB ...

  7. Android版-支付宝APP支付

    此项目已开源 赶快来围观 Start支持下吧 [客户端开源地址-JPay][服务端端开源地址-在com.javen.alipay 包名下] 上一篇详细介绍了微信APP支付 点击这里 此篇文章来详细介绍 ...

  8. 支付宝APP支付开发- IOException : DER input, Integer tag error

    支付宝APP支付Java开发报错: 1 java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: I ...

  9. 支付宝APP支付开发- IOException : DerInputStream.getLength(): lengthTag=127, too big.

    支付宝APP支付Java开发报错: IOException : DerInputStream.getLength(): lengthTag=127, too big. 后来排查是因为没有设置私钥.

随机推荐

  1. java上传图片,把图片存到本地

    思路:js通过FileReader获取图片的Base64,Java解码用IO存到本地. HTML 代码 <input type="file" ng-model="f ...

  2. JavaScript-rem字体自适应

    给html标签上添加 id=“FontSize”: 你期望满屏的rem值,如: <html font-size:100px></html> 我的主要内容为1200px,那么我的 ...

  3. ZOJ 3490 String Successor(模拟)

    Time Limit: 2 Seconds Memory Limit: 65536 KB The successor to a string can be calculated by applying ...

  4. Express入门教程:一个简单的博客

    来自:  http://ourjs.com/detail/56b2a6f088feaf2d031d2468 Express 简介 Express 是一个简洁而灵活的 node.js Web应用框架, ...

  5. [NSUserDefaults]的使用:登陆后不再显示登录界面。

    简介: NSUserDefaults是IOS应用用来存储用户偏好和配置信息的途径,就像是一个数据库,但是它通过键值对(key-value)的方式存储. 比如["Thematrix" ...

  6. 初探runtime

    1 简介 runtime,也叫它运行时系统.它是用c写的一套API,oc代码底层实现全都依赖它.我们说它是运行时,是相比编译,在程序编译完成之后,一些对象可通过runtime来干一些在编译时看似不可能 ...

  7. Spring 框架整合JUnit单元测试

    // 整合之前 public class Demo{ @Test public void fun(){ // 获取工厂,加载配置文件 ApplicationContext ac = new Class ...

  8. Runtime Error! R6025-pure virtual function call 问题怎么解决

    一.故障现象:1.360软件的木马查杀.漏洞修复等组件不能使用,提示runtime error2.暴风影音等很多软件不能正常使用3.设备管理器不能打开,提示“MMC 不能打开文件”4.部分https安 ...

  9. python内存泄露查找

    1 前言: 1.1 像Java程序一样,虽然Python本身也有垃圾回收的功能,但是同样也会产生内存泄漏的问题 1.2 在Python程序里,内存泄漏是由于一个长期持有的对象不断的往一个dict或者l ...

  10. redis的数据类型与应用场景(二)

    1. 如何学习 redis有好多数据类型,有这么多数据类型,我们不可能每个都记得完完全全.但是我们必须知道它有哪些数据类型,每个数据类型是怎样的,有什么作用.redis的每一个数据类型都有一大堆命令, ...