在加上ai的神辅助下整蛊了一周多的代码才写出来的3.0大更新,期间包括破解了cursor的时间 (:doge)
整体页面大更新,让你的眼睛看起来更舒服了
gitee: Pass Assistant前端: 何平安魔改time sea后的gpt前端部分
Pass Assistant后端: 基于time sea修改后的gpt
更新内容
图床模块优化更新

新增了公共图床,可以将自己的图片设为私有或公有,共有任何人都可以查看,布局也比以前的无css叙利亚风更好看,站长也更有钱了,普通用户上限20张了(原来10张)后续3.1或3.2将添加用IT币来扩容图床
外联导航模块



反正就是看起来更舒服了页面,以前的显示还有bug
新增”关于我”模块

就是如图,一个非常简单的页面,但是使用了新技术lottie动态图,里面还有我的岁月史书~
还有许多细处的更新,反正就让这个网站看起来像人做的了
虎皮椒支付接入
因为平安我没法注册微信或支付宝支付商家(学生党懂得都懂),发现了三方支付代理,就选了虎皮椒支付(花了88大洋开户了支付宝,因为就在它就在重庆开的公司跑路了我也可以线下单杀),下面是我在我网站接入的java代码理解,全是自己手敲的ai都写不出来。
官网:虎皮椒-个人支付微信支付宝个人支付接口,个人网站收款API接口
官方api接口
支付网关接口URL:
1
| https://api.xunhupay.com/payment/do.html (设置为可配置的变量,以便接口变更时方便修改)
|
传参方式:Post
使用curl的post方式传参数,并直接获取json返回值,引导客户跳转到支付链接。
# |
参数名 |
含义 |
类型 |
说明 |
1 |
version |
API 版本号 |
string(24) |
必填。目前为1.1 |
2 |
appid |
APP ID |
string(32) |
必填。填写虎皮椒的APPID,不是小程序APPID |
3 |
trade_order_id |
商户订单号 |
string(32) |
必填。请确保在当前网站内是唯一订单号,只能是数字、大小写字母_-* |
4 |
total_fee |
订单金额(元) |
decimal(18,2) |
必填。单位为人民币 元,没小数位不用强制保留2位小数 |
5 |
title |
订单标题 |
string(128) |
必填。商户订单标题(不能超过127个字符或者42个汉字,不能有表情符号) |
6 |
time |
当前时间戳 |
int(11) |
必填。PHP示例:time() |
7 |
notify_url |
通知回调网址 |
string(128) |
必填。用户支付成功后,我们服务器会主动发送一个post消息到这个网址(注意:当前接口内,SESSION内容无效,手机端不支持中文域名) |
8 |
return_url |
跳转网址 |
string(128) |
可选。用户支付成功后,我们会让用户浏览器自动跳转到这个网址 |
9 |
callback_url |
商品网址 |
string(128) |
可选。用户取消支付后,我们可能引导用户跳转到这个网址上重新进行支付 |
10 |
plugins |
名称 |
string(128) |
可选。 用于识别对接程序或作者 |
11 |
attach |
备注 |
text |
可选。备注字段,可以传入一些备注数据,回调时原样返回 |
12 |
nonce_str |
随机值 |
string(32) |
必填。作用:1.避免服务器页面缓存,2.防止安全密钥被猜测出来 |
13 |
hash |
签名 |
string(32) |
必填。 |
14 |
type |
支付通道类型 |
string(32) |
微信H5支付请填”WAP”,微信小程序支付请填”JSAPI” ,请参考小程序demo对接小程序支付,微信内支付请勿填写”JSAPI”,支付网关为:https://api.xunhupay.com 跳转小程序APPID:wx2574b5c5ee8da56b,其他支付网关跳转小程序APPID:wx402faa5bd5eda155,(支付宝不需要此参数) |
15 |
wap_url |
网站域名 |
string(50) |
网站域名,H5支付通道请填你网站域名,小程序支付请填支付网关(例如:https://api.dpweixin.com)。(支付宝不需要此参数) |
16 |
wap_name |
网站名称 |
string(50) |
店铺名称或网站域名,长度32或以内,H5支付通道请求必填。(支付宝不需要此参数) |
请求返回:
# |
参数名 |
含义 |
类型 |
说明 |
1 |
oderid |
订单id |
int |
订单id(此处有个历史遗留错误,返回名称是openid,值是orderid,一般对接不需要这个参数) |
2 |
url_qrcode |
二维码地址(PC端使用) |
string(156) |
二维码有效期五分钟,PC端可将该参数展示出来进行扫码支付,不用再转二维码,需自己处理跳转 |
3 |
url |
请求url(手机端专用,PC端已停用) |
string(155) |
只需跳转此参数即可,系统会自动判断是微信端还是手机端,自动返回return_url,不能先显示“url_qrcode”二维码,再跳转“url”链接 |
4 |
errcode |
错误码 |
int |
|
5 |
errmsg |
错误信息 |
string(8) |
错误信息具体值 |
6 |
hash |
签名 |
string(32) |
数据签名,参考下面签名算法 |
HASH生成的步骤如下:
第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
特别注意以下重要规则:
- 参数名ASCII码从小到大排序(字典序);
- 如果参数的值为空不参与签名;
- 参数名区分大小写;
- 验证调用返回或微信主动通知签名时,传送的hash参数不参与签名,将生成的签名与该hash值作校验。
- 微信接口可能增加字段,验证签名时必须支持增加的扩展字段
第二步,在stringA最后拼接上APPSECRET(秘钥)
得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,得到hash值(32位小写)。
知道你们喜欢cv大法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| @Test public void pay(){ String appid = ""; String appsecret = ""; String url = "https://api.xunhupay.com/payment/do.html"; Map<String,Object> options = new HashMap<>(); options.put("version","1.1"); options.put("appid",appid); options.put("trade_order_id","1234567890"); options.put("total_fee","0.01"); options.put("title","Pass Assistant"); options.put("time", getSecondTimestamp(new Date())); options.put("notify_url","http://127.0.0.1:8601/pay/paycallback"); options.put("return_url","https://www.baidu.com"); options.put("callback_url","https://www.sina.com.cn/"); options.put("plugins","我是备注信息"); options.put("nonce_str","740969606"); StringBuilder sb = new StringBuilder(); options.entrySet().stream().sorted((e1,e2) -> e1.getKey().compareTo(e2.getKey())).forEach(a ->{ sb.append(a).append("&"); }); sb.deleteCharAt(sb.length()-1); sb.append(appsecret); String s = SecureUtil.md5(sb.toString()); System.out.println("我们生成的Hash 是:"+s); System.out.println("我们生成的time 是: "+options.get("time")); System.out.println(); options.put("hash", s); System.out.println("我们传递的参数有:"+options.toString()); System.out.println("开始调 虎皮椒支付 接口..."); String post = HttpUtil.post(url, options); System.out.println("结束调 虎皮椒支付 接口...\n"); System.out.println("虎皮椒支付 接口 响应的结果是:"+post+"\n"); try{ Map map = (Map)JSON.parse(post); map.keySet().stream().forEach(k -> { if (k == "url") { System.out.println("url二维码链接是: "+map.get(k)); } }); }catch (Exception e){ e.printStackTrace(); System.out.println("调 虎皮椒支付 时 出现了问题"); }
}
public static int getSecondTimestamp(Date date){ if (null == date) { return 0; } String timestamp = String.valueOf(date.getTime()); int length = timestamp.length(); if (length > 3) { return Integer.valueOf(timestamp.substring(0,length-3)); } else { return 0; } }
|
后来经过我的上十次测试,支付成功后回调(notify_url)没用,就选择第二种方法吧,页面每隔几秒查询次支付状况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| @Test public void test(){ String appid = ""; String appsecret = ""; String url = "https://api.xunhupay.com/payment/query.html"; Map<String,Object> options = new HashMap<>(); options.put("appid",appid); options.put("out_trade_order","1234567890"); options.put("time", getSecondTimestamp(new Date())); options.put("nonce_str","123546789"); StringBuilder sb = new StringBuilder(); options.entrySet().stream().sorted((e1,e2) -> e1.getKey().compareTo(e2.getKey())).forEach(a ->{ sb.append(a).append("&");}); sb.deleteCharAt(sb.length()-1); sb.append(appsecret); String s = SecureUtil.md5(sb.toString()); options.put("hash", s); System.out.println("我们传递的参数有:"+options); String post = HttpUtil.post(url, options); System.out.println("结束调 虎皮椒支付 接口...\n"); System.out.println("虎皮椒支付 接口 响应的结果是:"+post+"\n"); JSONObject jsonObject = JSON.parseObject(post); JSONObject dataObject = jsonObject.getJSONObject("data"); String status = dataObject.getString("status"); System.out.println(status); }
|
当然了上面的全只是测试类,下面上真的实战代码,也就是我的Pass Assistant的分享:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
| @Value("${hupijiao.appid}") private String AppId;
@Value("${hupijiao.appsecret}") private String AppSecret;
@Value("${hupijiao.webUrl}") private String webUrl;
@Override @Transactional(rollbackFor = Exception.class) public AlipayPayCodeVo generatePayQrCode(final Long productId) { Product product = productMapper.selectOne(new QueryWrapper<Product>().lambda().eq(Product::getProductId, productId)); if (product == null) { throw new OrdersException(ExceptionMessages.PRODUCT_NULL_ERR, 500); } String url = "https://api.xunhupay.com/payment/do.html"; Map<String,Object> options = new HashMap<>(); options.put("version","1.1"); options.put("appid",AppId); SecureRandom secureRandom = new SecureRandom(); StringBuilder stringBuilder = new StringBuilder(12); for (int i = 0; i < 12; i++) { stringBuilder.append(secureRandom.nextInt(12)); } String randomNumber = stringBuilder.toString(); options.put("trade_order_id",randomNumber); String formattedNumber = String.format("%.2f", product.getProductPrice()); options.put("total_fee",formattedNumber); options.put("title",product.getProductName()); options.put("time", getSecondTimestamp(new Date())); options.put("notify_url","https://java.hepingan.top/pay/paycallback"); options.put("return_url",webUrl+"/#/user_view"); options.put("callback_url",webUrl+"/#/user_view"); options.put("plugins","您支付后的IT币(虚拟货币)将只用于Pass Assistant站内消费."); SecureRandom secureRandom2 = new SecureRandom(); StringBuilder stringBuilder2 = new StringBuilder(10); for (int i = 0; i < 10; i++) { stringBuilder2.append(secureRandom2.nextInt(10)); } String randomNumber2 = stringBuilder2.toString(); options.put("nonce_str",randomNumber2); StringBuilder sb = new StringBuilder(); options.entrySet().stream().sorted((e1,e2) -> e1.getKey().compareTo(e2.getKey())).forEach(a ->{ sb.append(a).append("&");}); sb.deleteCharAt(sb.length()-1); sb.append(AppSecret); String s = SecureUtil.md5(sb.toString()); options.put("hash", s); String post = HttpUtil.post(url, options); try{ Map<String, Object> map = (Map<String, Object>) JSON.parse(post); String payUrl = (String) map.get("url"); LocalDateTime createdTime = LocalDateTime.now(); Orders orders = new Orders() .setOrdersId(randomNumber) .setUserId(UserUtils.getCurrentLoginId()) .setCreatedTime(createdTime) .setUpdateTime(createdTime) .setProductId(productId) .setProductName(product.getProductName()) .setProductPrice(product.getProductPrice()) .setState(0); ordersMapper.insert(orders); return new AlipayPayCodeVo() .setOrdersId(orders.getOrdersId()) .setCreatedTime(orders.getCreatedTime()) .setProductName(orders.getProductName()) .setProductPrice(orders.getProductPrice()) .setPayUrl(payUrl); }catch (OrdersException e){ e.printStackTrace(); return null; }
}
public static int getSecondTimestamp(Date date){ if (null == date) { return 0; } String timestamp = String.valueOf(date.getTime()); int length = timestamp.length(); if (length > 3) { return Integer.valueOf(timestamp.substring(0,length-3)); } else { return 0; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
|
@Override public String paymentStatus(final String orderNo) { String url = "https://api.xunhupay.com/payment/query.html"; Map<String,Object> options = new HashMap<>(); options.put("appid",AppId); options.put("out_trade_order",orderNo); options.put("time", getSecondTimestamp(new Date())); SecureRandom secureRandom2 = new SecureRandom(); StringBuilder stringBuilder2 = new StringBuilder(10); for (int i = 0; i < 10; i++) { stringBuilder2.append(secureRandom2.nextInt(10)); } String randomNumber2 = stringBuilder2.toString(); options.put("nonce_str",randomNumber2); StringBuilder sb = new StringBuilder(); options.entrySet().stream().sorted((e1,e2) -> e1.getKey().compareTo(e2.getKey())).forEach(a ->{ sb.append(a).append("&");}); sb.deleteCharAt(sb.length()-1); sb.append(AppSecret); String s = SecureUtil.md5(sb.toString()); options.put("hash", s); String post = HttpUtil.post(url, options);
JSONObject jsonObject = JSON.parseObject(post); JSONObject dataObject = jsonObject.getJSONObject("data"); String status = dataObject.getString("status"); System.out.println(status); if (Objects.equals(status, "OD")){ ordersMapper.update(null,new UpdateWrapper<Orders>() .lambda() .eq(Orders::getOrdersId,orderNo) .set(Orders::getState,1) .set(Orders::getPayTime,LocalDateTime.now())); Long frequency = userMapper.getFrequencyById(UserUtils.getCurrentLoginId()); Orders orders = ordersMapper.selectOne(new QueryWrapper<Orders>() .lambda() .eq(Orders::getOrdersId,orderNo) .select(Orders::getProductId)); Product product = productMapper.selectOne(new QueryWrapper<Product>() .lambda() .eq(Product::getProductId, orders.getProductId()) .select(Product::getFrequency)); userMapper.update(null,new UpdateWrapper<User>() .lambda() .eq(User::getUserId,UserUtils.getCurrentLoginId()) .set(User::getFrequency,frequency+product.getFrequency())); return "success"; }else if (Objects.equals(status, "WP")){ return "wait"; }else { return "cancel"; } }
|
前端:
1 2 3 4 5 6 7 8 9 10 11 12
| <div v-if="payying" style="text-align: center; padding-top: 100px" > <h1>请跳转到新的页面进行支付</h1> <h2 style="color: red">支付成功前请勿关闭或刷新该页面</h2> </div> <div v-if="showSucceed" style="text-align: center; padding-top: 100px"> <h1>恭喜您已成功支付</h1> <el-button type="primary" @click="router().push('/user_view')">查看</el-button> </div> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| async function alipayPay() { try { ElLoading.service({ fullscreen: true, text: "正在构建订单...", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", }); outcome.value = await alipayPayQrCode(productId.value); payVisible.value = false; payying.value = true; mainPageVisible.value = false; window.open(outcome.value.payUrl, '_blank'); let timerId = setInterval(async function () { let res = await alipayIsSucceed(outcome.value.ordersId); if (res === "success") { ElNotification({ title: "成功", message: "赞赏成功,可在我的赞赏中查看该赞赏记录", type: "success", }); showSucceed.value = true; await getUser(); clearInterval(timerId); } else if (res === "cancel") { showCover.value = true; ElNotification({ title: "订单已关闭", message: "长时间未支付,订单已关闭", type: "error", }); clearInterval(timerId); } }, 5000); } catch (e) { ElNotification({ title: "错误", message: e, type: "error", }); mainPageVisible.value = true; } finally { ElLoading.service().close(); } }
|
看得懂就看啦,把那个测试类看懂就会了,我这个仅供参考