目录
前言
1.实现工厂
1.1 支付接口类
1.2 具体实现(以支付宝为例)
1.配置信息 (需要补全)
2.实现类
1.3 工厂类
2.实现通用的支付接口
2.1支付策略Controller
2.2支付策略Service
3.前端实现
最近做了支付宝支付,但是因为之后也要对接微信支付,各种支付API的原理是一样的,就采用了工厂模式实现支付,下面是我的代码。
import com.alibaba.fastjson.JSONObject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface PayStrategy {
// 创建支付订单
String createOrder(SdopRecPay sdopRecPay, String json);
// 查询支付结果
boolean queryResult(String orderId);
// 同步
void returnPay(HttpServletRequest request, HttpServletResponse response);
//异步
JSONObject notifyPay(HttpServletRequest request, HttpServletResponse response);
}
public class AlipayConstant {
//沙箱
// 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
public static String appId = "";
// 商户私钥 沙箱
public static String merPrivateKey = "";
// 支付宝公钥
public static String aliPublicKey = "";
// 支付宝网关
public static String gatewayUrl = "https://openapi-sandbox.dl.alipaydev.com/gateway.do";
// 签名方式
public static String signType = "RSA2";
// 服务器异步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String notifyUrl = "https://www.szdsoft.cn/pay/sdop/plat/pay/notifyPay";
// 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String returnUrl = "https://www.szdsoft.cn/pay/sdop/plat/pay/returnPay";
// 字符编码格式
public static String charset = "utf-8";
// 自定义
// 特有字段 用来区分是否是支付支付
public static String uniqueFile = "auth_app_id";
// 支付类型编码 表示采用了支付宝支付
public static String payType = "alipay";
}
@Service
@Slf4j
public class AlipayService implements PayStrategy {
@Resource
private ClientCore clientCore;
@Resource
private SdopRecPayMapper sdopRecPayMapper;
@Override
public String createOrder(SdopRecPay sdopRecPay, String json) {
String pageRedirectionData = "";
if (sdopRecPay.getPayPlan() != null) {
sdopRecPay.setPayPlan(sdopRecPay.getPayActual());
}
sdopRecPay.setAuthTypeDesc(clientCore.mdm.getDescDict("SDOP_AUTH_TYPE", sdopRecPay.getAuthType(), "1"));
//获得初始化的AlipayClient
AlipayClient alipayClient = new DefaultAlipayClient(AlipayConstant.gatewayUrl, AlipayConstant.appId, AlipayConstant.merPrivateKey,
"json", AlipayConstant.charset, AlipayConstant.aliPublicKey, AlipayConstant.signType);
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
//异步接收地址,仅支持http/https,公网可访问
request.setNotifyUrl(AlipayConstant.notifyUrl);
//同步跳转地址,仅支持http/https
request.setReturnUrl(AlipayConstant.returnUrl);
/******必传参数******/
JSONObject bizContent = new JSONObject();
//商户订单号,商家自定义,保持唯一性
bizContent.put("out_trade_no", sdopRecPay.getPayId());
//支付金额,最小值0.01元
bizContent.put("total_amount", sdopRecPay.getPayActual().doubleValue());
//订单标题,不可使用特殊符号
bizContent.put("subject", sdopRecPay.getAuthTypeDesc());
//电脑网站支付场景固定传值FAST_INSTANT_TRADE_PAY
bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
request.setBizContent(bizContent.toString());
// 也可以是GET请求
AlipayTradePagePayResponse response = null;
sdopRecPay.setPayTime(new Date());
try {
log.info("调用统一收单下单并支付页面接口参数{}", bizContent.toString());
response = alipayClient.pageExecute(request, "POST");
log.info("调用统一收单下单并支付页面接口结果{}", response.getBody());
if (response.isSuccess()) {
System.out.println("调用成功");
pageRedirectionData = response.getBody();
} else {
sdopRecPay.setStatus("E");
pageRedirectionData = "调用失败";
}
} catch (AlipayApiException e) {
sdopRecPay.setStatus("E");
pageRedirectionData = "调用异常:" + e.getErrMsg();
}
sdopRecPayMapper.deleteById(sdopRecPay.getPayId());
sdopRecPay.setCreateJson(json);
sdopRecPayMapper.insert(sdopRecPay);
return pageRedirectionData;
}
/**
* 统一收单交易查询接口
*/
@Override
public boolean queryResult(String payId) {
boolean result = false;
//获得初始化的AlipayClient
AlipayClient alipayClient = new DefaultAlipayClient(AlipayConstant.gatewayUrl, AlipayConstant.appId, AlipayConstant.merPrivateKey,
"json", AlipayConstant.charset, AlipayConstant.aliPublicKey, AlipayConstant.signType);
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
JSONObject bizContent = new JSONObject();
// trade_no out_trade_no 二选一
bizContent.put("out_trade_no", payId);
request.setBizContent(bizContent.toString());
AlipayTradeQueryResponse response = null;
SdopRecPay sdopRecPay = new SdopRecPay();
sdopRecPay.setPayId(payId);
try {
log.info("调用统一收单下单并支付页面接口参数{}", bizContent.toString());
response = alipayClient.execute(request);
log.info("统一收单交易查询接口结果{}", response.getBody());
} catch (AlipayApiException e) {
sdopRecPay.setQueryMsg("调用异常:" + e.getErrMsg());
}
if (response != null && response.isSuccess()) {
result = true;
sdopRecPay.setQueryCode(response.getCode());
sdopRecPay.setQueryMsg(response.getMsg());
}
sdopRecPay.setQueryTime(new Date());
sdopRecPayMapper.updateByCond(sdopRecPay);
return result;
}
/**
* 同步回调
*/
@Override
public void returnPay(HttpServletRequest request, HttpServletResponse response) {
SdopRecPay sdopRecPay = new SdopRecPay();
String msg = "";
String status = "E";
try {
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), AlipayConstant.charset);
sdopRecPay.setPayTime(new Date());
sdopRecPay.setPayId(out_trade_no);
boolean signVerified = getSignVerified(request);
if (signVerified) {
msg = checkPayInfo(request);
if (StringUtil.isEmpty(msg)) {
status = "S";
this.queryResult(sdopRecPay.getPayId());
response.setContentType("text/html;charset=utf-8");
String returnResult = clientCore.tool.getGlobalConfigVal("SDOP_SYS_CONFIG:pay_retrun_url");
response.sendRedirect(returnResult);
}
}
sdopRecPay.setStatus(status);
sdopRecPayMapper.updateByCond(sdopRecPay);
} catch (Exception e) {
log.info("调用异常{}", e.getMessage());
}
}
/**
* 异步回调地址
*/
@Override
public JSONObject notifyPay(HttpServletRequest request, HttpServletResponse response) {
String result = "failure";
String message = "失败";
PrintWriter out = null;
JSONObject body = null;
try {
out = response.getWriter();
boolean signVerified = getSignVerified(request);
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), AlipayConstant.charset);
//交易状态
String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), AlipayConstant.charset);
//支付宝交易凭证号
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), AlipayConstant.charset);
//支付金额信息 渠道+金额
String fund_bill_list = new String(request.getParameter("fund_bill_list").getBytes("ISO-8859-1"), AlipayConstant.charset);
SdopRecPay sdopRecPay = sdopRecPayMapper.selectById(out_trade_no);
if (signVerified) {
message = checkPayInfo(request);
if (StringUtil.isEmpty(message)) {
if (trade_status.equals("TRADE_FINISHED") || trade_status.equals("TRADE_SUCCESS")) {
this.queryResult(sdopRecPay.getPayId());
body = JSONObject.parseObject(sdopRecPay.getCreateJson());
body.put("payId", out_trade_no);
}
if (trade_status.equals("TRADE_FINISHED")) {
//注意:
//不支持退款付款成功、支持退款,并且退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
message = "订单已完成";
} else if (trade_status.equals("TRADE_SUCCESS")) {
//注意:
//支持退款,付款完成后,支付宝系统发送该交易状态通知
message = "订单付款成功";
} else if (trade_status.equals("WAIT_BUYER_PAY")) {
message = "交易创建成功";
} else if (trade_status.equals("TRADE_CLOSED")) {
message = "交易关闭成功";
}
result = "success";
}
} else {
message = "验签失败";
}
sdopRecPay.setRetPayId(trade_no);
sdopRecPay.setRetCode(trade_status);
sdopRecPay.setRetMsg(StringUtil.isNotEmpty(message) ? message : fund_bill_list);
sdopRecPay.setRetTime(new Date());
sdopRecPayMapper.updateByCond(sdopRecPay);
out.println(result);
} catch (IOException e) {
message = "参数异常";
}
return body;
}
/**
* 验签
*/
private boolean getSignVerified(HttpServletRequest request) throws IOException {
//获取支付宝POST过来反馈信息
Map params = new HashMap<>(16);
Map requestParams = request.getParameterMap();
for (Iterator 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] + ",";
}
//乱码解决,这段代码在出现乱码时使用
//valueStr = new String(valueStr.getBytes("ISO-8859-1"), charset);
params.put(name, valueStr);
}
log.info("验签参数{}", params);
boolean signVerified = false; //调用SDK验证签名
try {
signVerified = AlipaySignature.rsaCheckV1(params, AlipayConstant.aliPublicKey, AlipayConstant.charset, AlipayConstant.signType);
} catch (AlipayApiException e) {
log.info("验签异常{}", e.getErrMsg());
}
return signVerified;
}
/**
* 验证其他信息
*/
private String checkPayInfo(HttpServletRequest request) throws UnsupportedEncodingException {
/*
1、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
2、暂无 校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
3、验证app_id是否为该商户本身。
4、验证该通知数据中的out_trade_no是否为商户系统中创建的订单号
*/
SdopRecPay sdopRecPay = null;
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), AlipayConstant.charset);
String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"), AlipayConstant.charset);
String seller_id = new String(request.getParameter("seller_id").getBytes("ISO-8859-1"), AlipayConstant.charset);
String app_id = new String(request.getParameter("app_id").getBytes("ISO-8859-1"), AlipayConstant.charset);
if (StringUtil.isNotEmpty(out_trade_no) && StringUtil.isNotEmpty(total_amount) && StringUtil.isNotEmpty(seller_id) && StringUtil.isNotEmpty(app_id)) {
sdopRecPay = sdopRecPayMapper.selectById(out_trade_no);
if (sdopRecPay == null) {
return "订单号不匹配";
}
BigDecimal amount = new BigDecimal(total_amount);
if (sdopRecPay.getPayActual().compareTo(amount) != 0) {
return "订单金额不匹配";
}
if (!app_id.equals(AlipayConstant.appId)) {
return "APPID不匹配";
}
} else {
return "必填参数不能为空";
}
return "";
}
}
/**
* 支付策略工厂
*/
@Component
public class PayStrategyFactory {
private final ApplicationContext applicationContext;
@Autowired
public PayStrategyFactory(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public PayStrategy getPayStrategy(String payType) {
if(AlipayConstant.payType.equals(payType)){
return applicationContext.getBean(AlipayService.class);
}
throw new ClientCustomException("没找到支付策略,请联系管理员!");
}
public PayStrategy getPayStrategyByPara(HttpServletRequest request) {
//支付宝回调
String auth_app_id = request.getParameter(AlipayConstant.uniqueFile);
if(StringUtil.isNotEmpty(auth_app_id)){
return getPayStrategy(AlipayConstant.payType);
}
throw new ClientCustomException("没找到支付策略,请联系管理员!");
}
}
// 支付
@PostMapping("/createOrder")
public void createOrder(@RequestBody SdopAuthBody sdopAuthBody, HttpServletRequest request, HttpServletResponse response) {
SdopCust loginUser = tokenService.getLoginUser(request);
sdopAuthBody.setLoginCustId(loginUser.getCustId());
payStrategyService.createOrder(sdopAuthBody, response);
}
// 查询
@PostMapping("/queryResult/{payId}/{payType}")
public ClientAjaxResult queryResult(@PathVariable String payId, @PathVariable String payType, HttpServletResponse response) {
boolean b = payStrategyService.queryResult(payId, payType);
return b ? ClientAjaxResult.success(b) : ClientAjaxResult.error("支付未成功");
}
// 同步
@GetMapping("/returnPay")
public void returnPay(HttpServletRequest request, HttpServletResponse response) {
payStrategyService.returnPay(request, response);
}
// 异步
@PostMapping("/notifyPay")
public void notifyPay(HttpServletRequest request, HttpServletResponse response) {
//支付宝必须是post请求
payStrategyService.notifyPay(request, response);
}
@Service
@Slf4j
public class PayStrategyService {
@Resource
private PayStrategyFactory payFactory;
@Resource
private SdopAuthService sdopAuthService;
/**
* 支付接口
* 参数 authType payPlan payActual payId
*/
public void createOrder(SdopAuthBody sdopAuthBody, HttpServletResponse httpResponse) {
PrintWriter out = null;
try {
// 重新计算预防篡改
sdopAuthBody = sdopAuthService.confirmInfo(sdopAuthBody);
PayStrategy alipay = payFactory.getPayStrategy(sdopAuthBody.getPayType());
SdopRecPay sdopRecPay = new SdopRecPay();
sdopRecPay.setPayPlan(sdopAuthBody.getPrice());
sdopRecPay.setPayActual(sdopAuthBody.getPrice());
sdopRecPay.setAuthType(sdopAuthBody.getAuthType());
/*ClientResult clientResult = clientCore.tool.getNumDocB("SDOP_PAY",null);
if(!clientResult.getStatus().equals("S")){
throw new ClientCustomException("创建支付号失败,请联系管理员");
}*/
sdopRecPay.setPayId(sdopAuthBody.getLoginCustId() + ClientUtilSeq.getSnowflake());
String json = JSON.toJSONString(sdopAuthBody);
String pageRedirectionData = alipay.createOrder(sdopRecPay, json);
if (StringUtil.isEmpty(pageRedirectionData)) {
throw new ClientCustomException("创建支付订单失败,请联系管理员");
}
httpResponse.setContentType("text/html;charset=utf-8");
out = httpResponse.getWriter();
out.println(pageRedirectionData);
} catch (IOException e) {
log.info("写入异常{}", e.getMessage());
}
}
/**
* 查询接口
* 参数 authType payPlan payActual payId
*/
public boolean queryResult(String payId, String payType) {
PayStrategy alipay = payFactory.getPayStrategy(payType);
return alipay.queryResult(payId);
}
/**
* 同步回调 通过特有参数判断是什么支付
*/
public void returnPay(HttpServletRequest request, HttpServletResponse response) {
PayStrategy alipay = payFactory.getPayStrategyByPara(request);
alipay.returnPay(request, response);
}
/**
* 异步回调地址 通过参数判断是什么支付
*/
public void notifyPay(HttpServletRequest request, HttpServletResponse response) {
PayStrategy alipay = payFactory.getPayStrategyByPara(request);
JSONObject body = alipay.notifyPay(request, response);
if (body != null) {
SdopAuthBody sdopAuthBody = JSONObject.toJavaObject(body, SdopAuthBody.class);
// 付款成功或者完成生成授权码
sdopAuthService.genAuthCode(sdopAuthBody);
}
}
}
// 支付
btnPay() {
if (this.submitFormCheck()) {
// 设置支付策略
this.objDataOne.payType = "alipay"
createOrder(this.objDataOne).then((response) =>{
const newWindow = window.open('');
newWindow.document.write(response);
newWindow.focus();
//document.write(response)
this.activeStep = 3;
this.dialogParams.retcode = "S"
})
}
},