前言:
- 项目中需要给订单生成支付二维码,然后扫码支付,支付成功回调,后端处理支付成功的业务
- 需要到支付宝开放平台申请沙箱账号(地址:https://open.alipay.com/platform/home.htm),小编用的是沙箱的支付环境(地址:https://openhome.alipay.com/platform/appDaily.htm?tab=info)
-
项目地址(gitee): https://gitee.com/qinenqi/online
springboot整合阿里支付 实现订单的支付宝支付(属于 online_project服务)
springboot 整合支付宝支付二维码
- 引入依赖
<!-- 支付宝支付jar包 -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.1.0</version>
</dependency>
- 修改配置文件
# APPID
alipay.appId:2016092400588349
alipay.privateKey:请填写自己的秘钥
alipay.notifyUrl:88/api/project/applyController/notify
alipay.signType:RSA2
alipay.charset:utf-8
alipay.gatewayUrl:https://openapi.alipaydev.com/gateway.do
spring.interface.ip:请填写自己的回调地址
- 新建实体类 ApplyOrder.java
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.LocalDateTime;
@AllArgsConstructor
@NoArgsConstructor
@Data
@Slf4j
public class ApplyOrder implements Serializable {
private Long id;
/**
* 订单编号 order_no
*/
private String orderNo;
/**
* 订单价格 price
*/
private String price;
/**
* 订单状态 1000:未支付 2000:已支付 3000:支付失败 4000:默认
*/
private int status;
/**
* 订单内容 订单内容
*/
private String content;
/**
* 商家信息 shop_name
*/
private String shopName;
/**
* 订单描述 description
*/
private String description;
/**
* 创建时间 create_time
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
/**
* 更新时间 update_time
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
/**
* 备注 remark
*/
private String remark;
/**
* 二维码url code_url
*/
private String codeUrl;
}
- 新建控制器 ApplyOrderController.java
import com.example.onlinecommon.utils.R;
import com.example.onlineproject.entry.ApplyOrder;
import com.example.onlineproject.service.ApplyOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@RestController
@RequestMapping("/applyController")
@Slf4j
public class ApplyOrderController {
@Autowired
private ApplyOrderService applyOrderService;
/**
* 根据订单 id 获取订单信息和支付二维码信息
* @param id
* @return
*/
@RequestMapping("/getApplyOrderCode")
public R getApplyOrderCode(@RequestParam Long id){
ApplyOrder applyOrderCode = applyOrderService.getApplyOrderCode(id);
return R.ok(applyOrderCode);
}
/**
* 阿里支付宝 回调
* @param request
* @return
*/
@PostMapping("/notify")
public String alipayNotify(HttpServletRequest request){
boolean signVerified = applyOrderService.checkSign(request.getParameterMap());
if(signVerified){//验证成功 total_amount
System.out.println("验证成功,去更新状态");
String out_trade_no = new String(request.getParameter("out_trade_no")); //商户订单号
String trade_no = new String(request.getParameter("trade_no"));//支付宝交易号
String trade_status = new String(request.getParameter("trade_status"));//交易状态
String price = new String(request.getParameter("total_amount"));//交易金额
log.info("交易状态——trade_status:" + trade_status);
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//如果有做过处理,不执行商户的业务程序
if(trade_status.equals("TRADE_FINISHED")){
//交易结束,不可退款
//注意:退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
//可执行修改订单状态等
return ("finished");
}else if (trade_status.equals("TRADE_SUCCESS")){
log.info("交易支付成功");
//交易支付成功
//注意:付款完成后,支付宝系统发送该交易状态通知
//可执行修改订单状态等
// return ("success");
return ("false");
}else if (trade_status.equals("WAIT_BUYER_PAY")) {
//交易创建,等待买家付款
//可执行修改订单状态等
return ("wait");
}else{
//未付款交易超时关闭,或支付完成后全额退款(交易失败)
//可执行修改订单状态等
return ("close");
}
}else{
System.out.println("验证失败,不去更新状态");
//可执行修改订单状态等
return ("fail");
}
}
}
- 新建service 和实现类 ApplyOrderService.java ApplyOrderServiceImpl.java
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.onlineproject.entry.ApplyOrder;
import java.util.Map;
public interface ApplyOrderService extends IService<ApplyOrder> {
/**
* 根据订单id 获取该订单的支付信息
* @param id
* @return
*/
public ApplyOrder getApplyOrderCode(Long id);
/**
* 回调方法必须调用的验签方法,在回调结果前调用,确保是由支付宝发起的请求
* @return boolean
*/
public boolean checkSign(Map<String,String[]> requestParams);
}
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.AlipayTradePrecreateRequest;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.onlinecommon.utils.TimeUtil;
import com.example.onlineproject.entry.ApplyOrder;
import com.example.onlineproject.mapper.ApplyOrderMapper;
import com.example.onlineproject.service.ApplyOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@Service
@Slf4j
public class ApplyOrderServiceImpl extends ServiceImpl<ApplyOrderMapper, ApplyOrder> implements ApplyOrderService {
@Value("${alipay.appId}")
private String appId;
@Value("${alipay.privateKey}")
private String privateKey;
@Value("${alipay.publicKey}")
private String publicKey;
@Value("${alipay.gatewayUrl}")
private String gateway;
@Value("${spring.interface.ip}")
private String ip;
@Value("${server.port}")
private String port;
@Value("${alipay.notifyUrl}")
private String notifyUrl;
@Autowired
private ApplyOrderMapper applyOrderMapper;
/**
* 根据订单id 获取该订单的支付信息
* @param id
* @return
*/
public ApplyOrder getApplyOrderCode(Long id){
ApplyOrder applyOrder = applyOrderMapper.selectById(id);
applyOrder = aliPay(applyOrder);
return applyOrder;
}
/**
* 1. 二维码有效期:默认2小时(计算时间是生成二维码链接开始计算)
* 2. 电脑网站支付生成的二维码,有效期默认为1分钟。
* 3. A用户使用支付宝扫码二维码生成订单后 ,B用户再去扫描同一二维码则会报“二维码已失效,请商家更换二维码后重新支付”
* @param order
* @return
*/
public ApplyOrder aliPay(ApplyOrder order) {
String shopName = order.getShopName();
String orderNo = order.getOrderNo();
String price = order.getPrice();
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
// 支付请求
request.setBizContent("{" +
" \"out_trade_no\":\"" + orderNo + "\"," +//商户订单号
" \"total_amount\":\"" + price + "\"," +
" \"subject\":\"" + shopName + "当面付" + "\"," +
" \"store_id\":\"00100\"," + // (必填) 商户门店编号,通过门店号和商家后台可以配置精准到门店的折扣信息,详询支付宝技术支持
" \"timeout_express\":\"5m\"}");//订单允许的最晚付款时间
AlipayTradePrecreateResponse response = null;
String url = "http://" + ip + ":" + notifyUrl; // 需要经过网关的 http://127.0.0.1:88/api/project/applyController/notify, 请根据自己的情况进行处理
request.setNotifyUrl(url); // 接口通知方式
//支付宝二维码URL
String qrCode = "";
AlipayClient alipayClient = new DefaultAlipayClient(gateway, appId, privateKey, "json", "utf-8", publicKey, "RSA2");
try {
response = alipayClient.execute(request);
if(response.isSuccess()){
System.out.println("调用成功");
} else {
System.out.println("调用失败");
}
if (!response.isSuccess()) {
throw new Exception("生成支付宝订单失败:" + response.getMsg());
}
qrCode = response.getQrCode();
} catch (Exception e) {
e.printStackTrace();
}
order.setCodeUrl(qrCode);
LocalDateTime currentTime = TimeUtil.getCurrentTime();
order.setUpdateTime(currentTime);
UpdateWrapper updateWrapper = new UpdateWrapper();
updateWrapper.eq("id", order.getId());
updateWrapper.set("code_url", qrCode);
updateWrapper.set("update_time", currentTime);
applyOrderMapper.update(null, updateWrapper);
return order;
}
/**
* 回调方法必须调用的验签方法,在回调结果前调用,确保是由支付宝发起的请求
* @return boolean
*/
public boolean checkSign(Map<String,String[]> requestParams){
Map<String,String> params = new HashMap<String,String>();//将异步通知中收到的所有参数都存放到 map 中
for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
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 = false; //调用SDK验证签名
try {
signVerified = AlipaySignature.rsaCheckV1(params, publicKey, "utf-8", "RSA2");
} catch (AlipayApiException e) {
log.error("支付宝验签接口请求失败,resp={}", e.getErrMsg());
}
return signVerified;
}
}
- 新建mapper: ApplyOrderMapper.java
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.onlineproject.entry.ApplyOrder;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface ApplyOrderMapper extends BaseMapper<ApplyOrder> {
}
后端效果:
前端页面:
请根据自己的情况,完善前端vue页面
这是支付宝的支付页面
版权声明:本文为weixin_41695138原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。