Open-his 支付系统
1.目的
就是为用户提供一些支付的手段,提供类似银联支付,微信支付,支付宝支付等等的手段!
2.说明
我们在众多的支付系统里面,应该优先选择微信支付(因为我们现在微信的小程序,但是微信支付必须 是企业用户,而且你的小程序已经上线 2 周左右,你才能使用微信支付) 所以我们这里面只能选择支付宝支付了 因为支付宝宝的支付流程和微信支持的流程非常相似,我们会一个,别的道理差不多
3.申请支付宝的账号
3.1扫码登录
3.2账号申请
3.3下载支付宝测试版
安装好的效果
3.4登录测试版支付宝
3.5登录成功后
3.6充值
4.生成公钥和私钥
5.集成支付宝扫码支付功能
5.1创建项目 alipay-demo
下载demo
5.2导入依赖包
5.2.1修改pom文件
<!--引入支付宝相关的jar包-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.3.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/alipay-sdk-java-3.3.0.jar</systemPath> </dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>alipay-trade-sdk-java</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/alipay-trade-sdk-1.0.jar</systemPath> </dependency>
5.3.创建zfbinfo.properties
5.5创建payService
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.demo.trade.config.Configs;
import com.alipay.demo.trade.model.builder.AlipayTradePrecreateRequestBuilder; import com.alipay.demo.trade.model.builder.AlipayTradeRefundRequestBuilder; import com.alipay.demo.trade.model.result.AlipayF2FPrecreateResult;
import com.alipay.demo.trade.model.result.AlipayF2FRefundResult;
import com.alipay.demo.trade.service.AlipayTradeService;
import com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.HashMap; import java.util.Map;
/**
* @Author:
* 支付类
*/
public class PayService {
//输出日志
static Log log = LogFactory.getLog("trade_precreate"); //支付定当关付的对象
static AlipayTradeService tradeService;
//初始化对象
static {
// 一定要在创建AlipayTradeService之前设置参数
Configs.init("zfbinfo.properties");
tradeService = new AlipayTradeServiceImpl.ClientBuilder().build(); }
// 商户操作员编号,添加此参数可以为商户操作员做销售统计 static String operatorId = "test_operator_id";
// (必填) 商户门店编号,通过门店号和商家后台可以配置精准到门店的折扣信息,详询支付宝技术支 持
static String storeId = "test_store_id";
// 支付超时,定义为120分钟
static String timeoutExpress = "120m";
/**
* 支付的方法
* @param outTradeNo (必填) 商户网站订单系统中唯一订单号,64个字符以内,只能包含字母、 数字、下划线, 需保证商户系统端不能重复,建议通过数据库sequence生成,
* @param subject (必填) 订单标题,粗略描述用户的支付目的。如“喜士多(浦东店)消费”
* @param totalAmount (必填) 订单总金额,单位为元,不能超过1亿元
* @param undiscountableAmount (可选) 订单不可打折金额,可以配合商家平台配置折扣活 动,如果酒水不参与打折,则将对应金额填写至此字段
* @param body 订单描述,可以对交易或商品进行一个详细地描述,比如填写"购买商品2件共15.00 元"
* @param notifyUrl /支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置
* @return
*/
public static Map<String,Object> pay(String outTradeNo,
String subject,
String totalAmount,
String undiscountableAmount,
String body,
String notifyUrl
){
System.out.println(notifyUrl);
AlipayTradePrecreateRequestBuilder builder =new AlipayTradePrecreateRequestBuilder()
.setSubject(subject)
.setTotalAmount(totalAmount)
.setOutTradeNo(outTradeNo)
.setUndiscountableAmount(undiscountableAmount)
.setBody(body)
.setOperatorId(operatorId)
.setStoreId(storeId)
.setTimeoutExpress(timeoutExpress)
.setNotifyUrl(notifyUrl);
// .setNotifyUrl("http://www.test-notify-url.com");//支付宝服务器主动通 知商户服务器里指定的页面http路径,根据需要设置
//发起支付
8
AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder); Map<String,Object> map=new HashMap<>();
String msg;
Integer code;
switch (result.getTradeStatus()) {
case SUCCESS:
log.info("支付宝预下单成功: )");
AlipayTradePrecreateResponse res = result.getResponse();
//得到支付码,本质就是一个URL
String qrCode=res.getQrCode();
map.put("qrCode",qrCode);
msg="下单成功";
code=200;
break;
case FAILED:
log.error("支付宝预下单失败!!!");
msg="下单失败";
code=500;
break;
case UNKNOWN:
log.error("系统异常,预下单状态未知!!!");
msg="系统异常";
code=404;
break;
default:
log.error("不支持的交易状态,交易返回异常!!!"); msg="不支持的交易状态";
code=404;
break;
}
map.put("msg",msg);
map.put("code",code);
return map;
}
}
5.6测试支付
import java.util.Map;
/**
* @Author:
*/
public class TestPay {
public static void main(String[] args) {
String outTradeNo="OD123124124ABCDE94";
String subject="SXT-医疗管理系统支付平台";
String totalAmount="100";
String undiscountableAmount=null;
String body="买药用的";
String notifyUrl="http://45314rh250.qicp.vip/pay/callback/"+outTradeNo; Map<String, Object> pay = PayService.pay(outTradeNo, subject, totalAmount, undiscountableAmount, body, notifyUrl);
System.out.println(pay);
}
}
10
http://45314rh250.qicp.vip/pay/callback/OD123124124ABCDE94
16:21:48.372 [main] INFO
com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl - trade.precreate bizContent:
{"out_trade_no":"OD123124124ABCDE94","total_amount":"100","subject":"SXT-医疗管理 系统支付平台","body":"买药用
的","operator_id":"test_operator_id","store_id":"test_store_id","timeout_express" :"120m"}
16:21:48.925 [main] DEBUG sdk.biz.err - 2030-02-13
16:21:48^_^https://openapi.alipaydev.com/gateway.do?alipay_sdk=alipay-sdk-java- 3.3.0&app_id=2021000118647783&biz_content=%7B%22out_trade_no%22%3A%22OD123124124 ABCDE94%22%2C%22total_amount%22%3A%22100%22%2C%22subject%22%3A%22SXT- %E5%8C%BB%E7%96%97%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%E6%94%AF%E4%BB%98%E5%B9%B 3%E5%8F%B0%22%2C%22body%22%3A%22%E4%B9%B0%E8%8D%AF%E7%94%A8%E7%9A%84%22%2C%22ope rator_id%22%3A%22test_operator_id%22%2C%22store_id%22%3A%22test_store_id%22%2C%2 2timeout_express%22%3A%22120m%22%7D&charset=utf- 8&format=json&method=alipay.trade.precreate¬ify_url=http%3A%2F%2F45314rh250.q icp.vip%2Fpay%2Fcallback%2FOD123124124ABCDE94&sign=PGusujk2v%2F3Qy4dPwTJldcjJ8AE 30VWpHlvFdEPPHsrWlkWD65f7fkAe8cxdxGYUShwatdEIe9NUhJixAUfZ4G3h30fpn8nAjtxCSRSG%2B 51C3MLQDM%2FMeCf1Gb3P6%2Fr11VFBu8vYTs1kjaTl1XAiFCCSRdseD1A3AzUdSvLcJxMPGAzYxICfq EVQjnqswqGN5%2FQaOjvSm3GTCSBbAt9rxA9t6%2Bq4JABZjFX4lurHeocnSBTRAbRQb%2FtD%2FpErZ AR2eUm%2B8FEeLg2l0U6kBNZjvPZmeYs%2FyIXllCoeq3bhhNjPTrANBZoG3ERDOomRMVC95ZsCrpBmB PJrOr4VnbmAtQ%3D%3D&sign_type=RSA2×tamp=2022-02-13+16%3A21%3A48&version=1.0 16:21:50.223 [main] INFO sdk.biz.err -
Summary^_^10000^_^null^_^ProtocalMustParams:charset=utf-
8&method=alipay.trade.precreate&sign=PGusujk2v/3Qy4dPwTJldcjJ8AE30VWpHlvFdEPPHsr WlkWD65f7fkAe8cxdxGYUShwatdEIe9NUhJixAUfZ4G3h30fpn8nAjtxCSRSG+51C3MLQDM/MeCf1Gb3 P6/r11VFBu8vYTs1kjaTl1XAiFCCSRdseD1A3AzUdSvLcJxMPGAzYxICfqEVQjnqswqGN5/QaOjvSm3G TCSBbAt9rxA9t6+q4JABZjFX4lurHeocnSBTRAbRQb/tD/pErZAR2eUm+8FEeLg2l0U6kBNZjvPZmeYs
/yIXllCoeq3bhhNjPTrANBZoG3ERDOomRMVC95ZsCrpBmBPJrOr4VnbmAtQ==¬ify_url=http:// 45314rh250.qicp.vip/pay/callback/OD123124124ABCDE94&version=1.0&app_id=202100011 8647783&sign_type=RSA2×tamp=2022-02-13 16:21:48^_^ProtocalOptParams:alipay_sdk=alipay-sdk-java- 3.3.0&format=json^_^ApplicationParams:biz_content= {"out_trade_no":"OD123124124ABCDE94","total_amount":"100","subject":"SXT-医疗管理 系统支付平台","body":"买药用
的","operator_id":"test_operator_id","store_id":"test_store_id","timeout_express" :"120m"}^_^553ms,1282ms,16ms
16:21:50.223 [main] INFO
com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl -
{"alipay_trade_precreate_response":
{"code":"10000","msg":"Success","out_trade_no":"OD123124124ABCDE94","qr_code":"h ttps:\/\/qr.alipay.com\/bax04481md03pfwbl1ay00ad"},"sign":"bRlOc5cL2psx0MeNwLVwB kMwTlvQA79UjNNV76yim3ImkxM643DiXU5Q0D04wfYoNVUvELWpJ9NqNo0bztr0gT1t8nafOkqnOwSN0 525DjT8gWwEldyyqsCjlCTpgDh66LGK3/4JbuYXysb5bhKQHzAVB5Ux8TxK2sbo1tpSYjCRlBc5x6GzS FQ2f8H+cPQgjcikDOILS5ZGUG6dZZ3gGHraswLmlpAftkl8j6yB4i/o/lnhBTUnOerAnTubSTutH+ARp 0iiEMyG4EjVfp0bQso7Ll+EY+bbvqSXIXmL5Q5cRWKPZO21oGxPSSL+M16AFVShgvulFkU5sMyFB7/fa A=="}
16:21:50.223 [main] INFO trade_precreate - 支付宝预下单成功: )
{msg=下单成功, code=200, qrCode=https://qr.alipay.com/bax04481md03pfwbl1ay00ad}
5.7创建PayController回调方法
下载花生壳,配置回调地址
5.7.1编写controller
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.bjsxt.pay.AlipayConfig;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest; import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
* @Author:
*/
@RestController @RequestMapping("pay")
public class PayController {
//输出日志
static Log log = LogFactory.getLog("PayController");
@PostMapping("callback/{orderId}")
public void callback(@PathVariable String orderId, HttpServletRequest request) {
Map<String, String> parameterMap = this.getParameterMap(request);
String trade_status = parameterMap.get("trade_status");
if ("TRADE_SUCCESS".equals(trade_status)) {
try {
//验证是否为支付宝发来的信息
boolean singVerified = AlipaySignature.rsaCheckV1(parameterMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);
System.out.println(singVerified);//只有支付宝调用我们系统的接口才能去更 新系统订单状态
log.info("验证签名结果{}:" + singVerified);
String refund_fee = parameterMap.get("refund_fee");
if (StringUtils.isNotBlank(refund_fee)) {
//说明是退费
System.out.println("退费成功:退费的子订单ID为:" +
parameterMap.get("out_biz_no"));
//更新订单状态
} else {
//说明支付
System.out.println("收费成功,平台ID" +
parameterMap.get("trade_no"));
}
System.out.println(JSON.toJSON(parameterMap));
} catch (AlipayApiException e) {
e.printStackTrace();
log.error(orderId + "验证签名出现异常");
}
}else if("WAIT_BUYER_PAY".equals(trade_status)){
System.out.println("二维码已扫描,等待支付");
}
}
/**
* 获取request中的参数集合转Map
* Map<String,String> parameterMap = RequestUtil.getParameterMap(request) *
* @param request
* @return
*/
public Map<String, String> getParameterMap(HttpServletRequest request) {
Map<String, String> map = new HashMap<>();
Enumeration<String> paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) {
String paramName = paramNames.nextElement();
String[] paramValues = request.getParameterValues(paramName);
if (paramValues.length == 1) {
String paramValue = paramValues[0];
if (paramValue.length() != 0) {
map.put(paramName, paramValue);
}
}
}
return map;
}
}
13
5.7.2测试结果
当用户扫码之后会回调一次,支付成功之后会回调一次
5.8测试退费
修改PayService
/**
* 退费
* @param outTradeNo 外部应该交易ID
* @param tradeNo 平台在支付成之后返回的平台【属于支付宝平台的ID】
* @param refundAmount 退款金额
* @param refundReason 退款原因
* @param outRequestNo 是否支持部分退款
*/
public static Map<String,Object> payBack(String outTradeNo,String
tradeNo,String refundAmount,String refundReason,String outRequestNo){
AlipayTradeRefundRequestBuilder builder = new AlipayTradeRefundRequestBuilder()
.setOutTradeNo(outTradeNo)//outTradeNo tradeNo只需要有一个就行
.setTradeNo(tradeNo)
.setRefundAmount(refundAmount)
.setRefundReason(refundReason)
.setOutRequestNo(outRequestNo)
// .setNotifyUrl(notifyUrl)//没有用 因为这个回调地址就是收费时的回调地址 .setStoreId(storeId);
//退费请求
AlipayF2FRefundResult result = tradeService.tradeRefund(builder);
Map<String,Object> map=new HashMap<>();
Integer code=null;
String msg="";
switch (result.getTradeStatus()) {
case SUCCESS:
log.info("支付宝退款成功: )");
code=200;
msg=result.getResponse().getSubMsg();
break;
case FAILED:
log.error("支付宝退款失败!!!");
code=500;
msg=result.getResponse().getSubMsg(); break;
case UNKNOWN:
log.error("系统异常,订单退款状态未知!!!"); code=500;
msg=result.getResponse().getSubMsg();
break;
default:
log.error("不支持的交易状态,交易返回异常!!!"); code=500;
msg=result.getResponse().getSubMsg();
break;
}
map.put("code",code);
map.put("msg",msg);
return map;
}
创建测试类TestRefund
/**
* @Author:
* 测试退费
*/
public class TestRefund {
public static void main(String[] args) {
String outTradeNo="OD123124124ABCDEF5";
String tradeNo="2021110922001471560501815457";
String subject="SXT-医疗管理系统支付平台";
String refudAmount="60";
String refudReason="不想要了";
Map<String, Object> map = PayService.payBack(outTradeNo, tradeNo, refudAmount, refudReason, "BK12345681");
System.out.println(map);
}
}
15