支付宝移动支付安卓与Javaweb服务端的实现,更安全


1.注册企业账号;

2.创建应用 ;

3.配置应用 ;

4.开启支付APP支付 ;

5.签约,在支付宝开放平台中跟着步骤走就可以完成的操作,为对接做准备工作。

6.去管理中心得到应用的APPID;

7.用支付宝开放平台开发助手生成一一对密钥,分别是应用公钥和私钥在这里插入图片描述

8.用应用公钥去生成支付宝公钥,如图,点击 设置公钥在这里插入图片描述

9.填写异步通知URL;

然后就可以开始做服务端和客户端的开发啦!

4.服务端的实现


(1)首先要配置的东西:APP_ID、APP_PRIVATE_KEY(用支付宝开放平台开发助手生成的私钥)、ALIPAY_PUBLIC_KEY(支付宝公钥)。

对于怎么才能得到APPID。首先你得是企业账号才能接入支付宝支付,因为还要签约的。

在这里想说明一下,很多人都分不清私钥和公钥到底要怎么用,用哪一个?其实很简单。首先是打开这个支付宝开放平台开发助手,如下图

在这里插入图片描述

在这里插入图片描述

点击生成密钥,就会生成一个公钥和一个私钥。这个私钥就是我上面所说的APP_PRIVATE_KEY,但是这个生成的公钥有什么用呢?

这个公钥要把它放到支付宝开发平台那里,把它生成支付宝公钥,而生成的支付宝公钥,就是我上述所说的ALIPAY_PUBLIC_KEY。至于普通的公钥怎么才能生成支付宝公钥呢?

在这里插入图片描述

点击设置公钥,就能生成支付宝公钥了。

有写可能会问,为什么要这么做呢?我们要知道这三个密钥的作用分别是什么,用着才不会乱。

1.应用私钥:用于请求支付宝数据加签(放在服务端);

2.应用公钥:用于提供给支付宝,让支付宝去拿着公钥获取你私钥加签后的数据;(放在支付宝开发平台用于生成支付宝公钥);

3.支付宝公钥:是用来接收支付宝回调信息的(放在服务端);

这样说应该可以明白了吧。

(2)jar包:支付宝SDK.jar包在这里插入图片描述

(3)代码实现:springboot

在这里插入图片描述

6个java类

在这里插入图片描述

在这里插入图片描述

1.先来看看 DemoApplication.java

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication

public class DemoApplication {

public static void main(String[] args) {

SpringApplication.run(DemoApplication.class, args);

}

}

2.BaseEntity.java

public class BaseEntity {

private String code;

private String message;

private Object content;

public BaseEntity(String code, String message, Object content) {

this.code = code;

this.message = message;

this.content = content;

}

public String getCode() {

return code;

}

public void setCode(String code) {

this.code = code;

}

public String getMessage() {

return message;

}

public void setMessage(String message) {

this.message = message;

}

public Object getContent() {

return content;

}

public void setContent(Object content) {

this.content = content;

}

}

3.AlipayConfig.java 这个类是配置三个参数的

public class AlipayConfig {

public static final String APP_ID = “这里填签约后的APPID”;

public static final String APP_PRIVATE_KEY = “这里填用支付宝开放平台开发助手生成的应用私钥”;

public static final String ALIPAY_PUBLIC_KEY = “这里填支付宝公钥”;

public static final String CHARSET = “UTF-8”;

}

4.AlipayController.java 当客户端发起支付宝请求时,会先生成一个商户号,并根据这个商户号来新建订单表,订单状态暂时为未支付。当客户端支付成功之后,服务端会接收到异步通知,当通知支付成功的时候,可以把订单的状态改成已支付。但是要确保异步通知的URL必须是外网可以访问得到。

import com.alipay.api.AlipayApiException;

import com.alipay.api.AlipayClient;

import com.alipay.api.DefaultAlipayClient;

import com.alipay.api.internal.util.AlipaySignature;

import com.alipay.api.request.AlipayTradeAppPayRequest;

import com.alipay.api.response.AlipayTradeAppPayResponse;

import com.example.demo.bean.BaseEntity;

import com.example.demo.config.AlipayConfig;

import com.example.demo.utils.AliRequestParam;

import com.example.demo.utils.OrderNo;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;

import java.io.PrintWriter;

import java.util.HashMap;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

@RestController

public class AlipayController {

@SuppressWarnings(“unchecked”)

@RequestMapping(value = “/alipay”, method = RequestMethod.POST)

public Object alipayment(@RequestParam String payMoney) {

AlipayClient alipayClient = new DefaultAlipayClient(“https://openapi.alipay.com/gateway.do”,

AlipayConfig.APP_ID, AlipayConfig.APP_PRIVATE_KEY, “json”,

AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY,

“RSA2”);

String out_trade_no=OrderNo.getOutTradeNo();

System.out.println(“商户订单号”+out_trade_no);

//构建支付宝请求参数

AlipayTradeAppPayRequest request = AliRequestParam.startRequestAli(payMoney,out_trade_no);

try {

//这里和普通的接口调用不同,使用的是sdkExecute

AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);

System.out.println(response.getBody());//就是orderString 可以直接给客户端请求,客户端可以直接发起支付,无需再做处理。

@SuppressWarnings(“rawtypes”)

Map map = new HashMap();

map.put(“orderString”, response.getBody());

BaseEntity baseEntity = new BaseEntity(“200”, “支付宝下单成功”, map);

//这里做生成订单操作,订单状态为未支付

return baseEntity;

} catch (AlipayApiException e) {

e.printStackTrace();

}

BaseEntity baseEntity = new BaseEntity(“200”, “支付宝下单失败”, null);

return baseEntity;

}

//异步通知

@RequestMapping(value = “/pay_notify”,method = RequestMethod.POST)

public void notifyUrl(HttpServletResponse response,HttpServletRequest request) throws IOException, AlipayApiException {

System.out.println(“异步通知”);

PrintWriter out = response.getWriter();

request.setCharacterEncoding(“utf-8”);//乱码解决,这段代码在出现乱码时使用

//获取支付宝POST过来反馈信息

Map<String,String> params = new HashMap<String,String>();

Map<String,String[]> requestParams = request.getParameterMap();

for(String str :requestParams.keySet()){

String name = str;

String[] values = (String[]) requestParams.get(name);

String valueStr = “”;

for (int i = 0; i < values.length; i++) {

valueStr = (i == values.length - 1) ? valueStr + values[i]
valueStr + values[i] + “,”;

}

params.put(name, valueStr);

}

boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, “RSA2”); //调用SDK验证签名

if(!signVerified) {

System.out.println(“验签失败”);

out.print(“fail”);

return;

}

//商户订单号,之前生成的带用户ID的订单号

String out_trade_no = params.get(“out_trade_no”);

//支付宝交易号

String trade_no = params.get(“trade_no”);

//付款金额

String total_amount = params.get(“total_amount”);

//交易状态

String trade_status = new String(request.getParameter(“trade_status”).getBytes(“ISO-8859-1”),“UTF-8”);

// String appId=params.get(“app_id”);//支付宝分配给开发者的应用Id

// String notifyTime=params.get(“notify_time”);//通知时间:yyyy-MM-dd HH:mm:ss

// String gmtCreate=params.get(“gmt_create”);//交易创建时间:yyyy-MM-dd HH:mm:ss

String gmtPayment=params.get(“gmt_payment”);//交易付款时间

// String gmtRefund=params.get(“gmt_refund”);//交易退款时间

// String gmtClose=params.get(“gmt_close”);//交易结束时间

// String tradeNo=params.get(“trade_no”);//支付宝的交易号

// String outTradeNo = params.get(“out_trade_no”);//获取商户之前传给支付宝的订单号(商户系统的唯一订单号)

// String outBizNo=params.get(“out_biz_no”);//商户业务号(商户业务ID,主要是退款通知中返回退款申请的流水号)

// String buyerLogonId=params.get(“buyer_logon_id”);//买家支付宝账号

// String sellerId=params.get(“seller_id”);//卖家支付宝用户号

// String sellerEmail=params.get(“seller_email”);//卖家支付宝账号

// String totalAmount=params.get(“total_amount”);//订单金额:本次交易支付的订单金额,单位为人民币(元)

// String receiptAmount=params.get(“receipt_amount”);//实收金额:商家在交易中实际收到的款项,单位为元

// String invoiceAmount=params.get(“invoice_amount”);//开票金额:用户在交易中支付的可开发票的金额

// String buyerPayAmount=params.get(“buyer_pay_amount”);//付款金额:用户在交易中支付的金额

// String tradeStatus = params.get(“trade_status”);// 获取交易状态

if(trade_status.equals(“TRADE_FINISHED”)){

/此处可自由发挥/

//判断该笔订单是否在商户网站中已经做过处理

//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序

//如果有做过处理,不执行商户的业务程序

//注意:

//退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知

}else if (trade_status.equals(“TRADE_SUCCESS”)){

//这里就可以更新订单状态为已支付啦

}

out.print(“success”);

}

}

5.AliRequestParam.java

import com.alipay.api.domain.AlipayTradeAppPayModel;

import com.alipay.api.request.AlipayTradeAppPayRequest;

public class AliRequestParam {

public static AlipayTradeAppPayRequest startRequestAli(String payMoney,String trade_no) {

//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay

AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();

//SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。

AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();

model.setBody(“某公司”);

model.setSubject(“某商品”);

model.setOutTradeNo(trade_no);

model.setTimeoutExpress(“30m”);

model.setTotalAmount(payMoney);

model.setProductCode(“QUICK_MSECURITY_PAY”);

request.setBizModel(model);

request.setNotifyUrl(“这里填你服务端的地址+异步通知的地址,如:http://example.com/pay_notify”);//这里要注意的是,这个地址外网必须要能访问,不然服务端无法接收到异步通知的,你只需要把example.com改成你的ip地址和端口号即可,如果做了端口映射的话就只填ip地址即可

return request;

}

}

6.OrderNo.java

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.Locale;

import java.util.Random;

public class OrderNo {

/**

  • get the out_trade_no for an order. 生成商户订单号,该值在商户端应保持唯一(可自定义格式规范)

*/

public static String getOutTradeNo() {

SimpleDateFormat format = new SimpleDateFormat(“MMddHHmmss”, Locale.getDefault());

Date date = new Date();

String key = format.format(date);

Random r = new Random();

key = key + r.nextInt();

key = key.substring(0, 15);

return key;

}

}

7.application.properties

server.port=8080

8.pom.xml
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns=“http://maven.apache.org/POM/4.0.0” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”

xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd”>

4.0.0

com.example

demo

0.0.1-SNAPSHOT

jar

demo

Demo project for Spring Boot

org.springframework.boot

spring-boot-starter-parent

1.5.8.RELEASE

<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

<java.version>1.8</java.version>

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-starter-test

test

org.springframework.boot

spring-boot-maven-plugin

服务器到这就完成啦。

5.APP端的实现


在这里插入图片描述

在这里插入图片描述

1.依赖

//http请求

implementation ‘com.zhy:okhttputils:2.6.2’

implementation ‘com.squareup.okhttp3:okhttp:3.10.0’

implementation ‘com.alibaba:fastjson:1.2.39’

在这里插入图片描述

2…PayDemoActivity 活动

import android.content.Intent;

import android.os.Bundle;

import android.util.Log;

import android.view.View;

import android.widget.RadioButton;

import android.widget.RadioGroup;

import android.widget.Toast;

import androidx.fragment.app.FragmentActivity;

import com.alibaba.fastjson.JSON;

import com.alipay.sdk.app.EnvUtils;

import com.learn.agg.R;

import com.learn.agg.alipay.AlipayAck;

import com.learn.agg.alipay.AlipayHelper;

import com.learn.agg.alipay.URLInterface;

import com.zhy.http.okhttp.OkHttpUtils;

import com.zhy.http.okhttp.callback.StringCallback;

import okhttp3.Call;

/**

  • 重要说明:

  • 这里只是为了方便直接向商户展示支付宝的整个支付流程;所以Demo中加签过程直接放在客户端完成;

  • 真实App里,privateKey等数据严禁放在客户端,加签过程务必要放在服务端完成;

  • 防止商户私密数据泄露,造成不必要的资金损失,及面临各种安全风险;

*/

public class PayDemoActivity extends FragmentActivity {

/** 商户私钥,pkcs8格式 */

/** 如下私钥,RSA2_PRIVATE 或者 RSA_PRIVATE 只需要填入一个 */

/** 如果商户两个都设置了,优先使用 RSA2_PRIVATE */

/** RSA2_PRIVATE 可以保证商户交易在更加安全的环境下进行,建议使用 RSA2_PRIVATE */

/** 获取 RSA2_PRIVATE,建议使用支付宝提供的公私钥生成工具生成, */

public PayDemoActivity() {

}

@Override

protected void onCreate(Bundle savedInstanceState) {

EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);

super.onCreate(savedInstanceState);

setContentView(R.layout.pay_main);

RadioGroup radioGroup;

final RadioButton alipay;

alipay = findViewById(R.id.alipay);

radioGroup = findViewById(R.id.payWay_choose);

radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {

@Override

public void onCheckedChanged(RadioGroup radioGroup, int i) {

if (alipay.getId()==i){

}

}

});

}

/**

  • 支付宝支付业务

  • @param v

*/

public void payV2(View v) {

/**

  • 这里只是为了方便直接向商户展示支付宝的整个支付流程;所以Demo中加签过程直接放在客户端完成;

  • 真实App里,privateKey等数据严禁放在客户端,加签过程务必要放在服务端完成;

  • 防止商户私密数据泄露,造成不必要的资金损失,及面临各种安全风险;

  • orderInfo的获取必须来自服务端

  • 如果RSA2_PRIVATE RSA_PRIVATE都设置了,那么我是优先选择RSA2_PRIVATE,因为更加安全

*/

//这里是用OkHttpUtils向服务器发起请求

String url = URLInterface.BASE_URL + “/alipay”;

String paymoney = “0.05”;//分为单位 1==1元

OkHttpUtils

.post()

.url(url)

.addParams(“payMoney”, paymoney )

.build()

.execute(new StringCallback() {

@Override

public void onError(Call call, Exception e, int id) {

Toast.makeText(PayDemoActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();

}

@Override

public void onResponse(String response, int id) {

AlipayAck alipayAck = JSON.parseObject(response, AlipayAck.class);

Toast.makeText(PayDemoActivity.this, alipayAck.getMessage(), Toast.LENGTH_SHORT).show();

testAliPay(alipayAck.getContent().getOrderString());

}

});

}

private void testAliPay(String orderInfo) {

AlipayHelper mAlipayHelper = new AlipayHelper();

mAlipayHelper.startAlipay(this, orderInfo, new AlipayHelper.OnPayClickListener() {

@Override

public void paySuccess() {

//支付成功

Log.d(“tag”, “paySuccess: 哈哈哈”);

Toast.makeText(PayDemoActivity.this,“支付成功”,Toast.LENGTH_LONG).show();

//支付成功的操作

}

@Override

public void payFailure() {

//支付失败

Log.d(“tag”, "payFailure: ");

}

});

}

}

3.AlipayAck.java

public class AlipayAck extends BaseEntity {

private ContentBean content;

public ContentBean getContent() {

return content;

}

public void setContent(ContentBean content) {

this.content = content;

}

public static class ContentBean {

private String orderString;

private String out_trade_no;

public String getOut_trade_no() {

return out_trade_no;

}

public void setOut_trade_no(String out_trade_no) {

this.out_trade_no = out_trade_no;

}

public String getOrderString() {

return orderString;

}

public void setOrderString(String orderString) {

this.orderString = orderString;

}

}

}

4.AlipayHelper.java

import android.annotation.SuppressLint;

import android.app.Activity;

import android.os.Handler;

import android.os.Message;

import android.text.TextUtils;

import android.util.Log;

import com.alipay.sdk.app.PayTask;

import java.util.Map;

public class AlipayHelper {

private static final int SDK_PAY_FLAG = 1;

private static AlipayHelper mAlipayHelper = new AlipayHelper();

private OnPayClickListener onPayClickListener;

//支付成功接口回调

public interface OnPayClickListener {

void paySuccess();

void payFailure();

}

public void startAlipay(final Activity activity, final String orderInfo, OnPayClickListener onPayClickListener) {

if (onPayClickListener == null || activity == null || orderInfo == null) {

return;

}

this.onPayClickListener = onPayClickListener;

Runnable payRunnable = new Runnable() {

@Override

public void run() {

PayTask alipay = new PayTask(activity);

Map<String, String> result = alipay.payV2(orderInfo, true);

Log.i(“msp”, result.toString());

Message msg = new Message();

msg.what = SDK_PAY_FLAG;

msg.obj = result;

mHandler.sendMessage(msg);

}

};

Thread payThread = new Thread(payRunnable);

payThread.start();

}

@SuppressLint(“HandlerLeak”)
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

Android开发除了flutter还有什么是必须掌握的吗?

相信大多数从事Android开发的朋友们越来越发现,找工作越来越难了,面试的要求越来越高了

除了基础扎实的java知识,数据结构算法,设计模式还要求会底层源码,NDK技术,性能调优,还有会些小程序和跨平台,比如说flutter,以思维脑图的方式展示在下图;

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

msg.what = SDK_PAY_FLAG;

msg.obj = result;

mHandler.sendMessage(msg);

}

};

Thread payThread = new Thread(payRunnable);

payThread.start();

}

@SuppressLint(“HandlerLeak”)
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-H83OlH8u-1713634711104)]

[外链图片转存中…(img-hQubokZo-1713634711106)]

[外链图片转存中…(img-SdkQBU8u-1713634711108)]

[外链图片转存中…(img-LLTWHOvH-1713634711110)]

[外链图片转存中…(img-PDurO4GF-1713634711111)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

Android开发除了flutter还有什么是必须掌握的吗?

相信大多数从事Android开发的朋友们越来越发现,找工作越来越难了,面试的要求越来越高了

除了基础扎实的java知识,数据结构算法,设计模式还要求会底层源码,NDK技术,性能调优,还有会些小程序和跨平台,比如说flutter,以思维脑图的方式展示在下图;

[外链图片转存中…(img-YATYbDEm-1713634711112)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值