支付宝沙箱支付教程

支付宝官方沙箱文档:电脑网站支付快速接入 - 支付宝文档中心 (alipay.com)

1.准备工作

(1). 先到支付宝开放平台注册账号并登录
(2). 登录后点进控制台,然后往下滑找到沙箱
(3). 选择自定义密钥,并选择公钥模式并点击设置
(4). 下载支付宝开放平台密钥工具(去支付宝开放平台官网里下载),把生成的应用公钥复制到上一步
(5). 创建一个IDEA项目

正式流程:

(1).引入支付宝相关依赖
<!--SDK-->
<dependency>
   <groupId>com.alipay.sdk</groupId>
   <artifactId>alipay-sdk-java</artifactId>
   <version>4.22.57.ALL</version>
</dependency>
(2). 创建一个AlipayClientConfig类,把之前沙箱里的信息都填进来
(3). 创建一个AlipayController,并调用实现类的tradeCreate方法(自己写的方法,下文有),别忘了加跨域@CrossOrigin注解
(4). tradeCreate实现类代码,里面的orderInfoService要自己创建,里面代码是关于订单信息的
@Service
@Slf4j
public class AlipayServiceImpl implements AlipayService {
    @Autowired
    private OrderInfoService orderInfoService;

    @Transactional
    @Override
    public String tradeCreate(Long productId) {

        try {
            log.info("生成订单");
            OrderInfo orderInfo = orderInfoService.createOrderByProductId(productId);
           //调用支付宝接口
            AlipayClient alipayClient = new DefaultAlipayClient(AlipayClientConfig.gateway_url, AlipayClientConfig.app_id, AlipayClientConfig.merchant_private_key, "json", "utf-8", AlipayClientConfig.public_key, "RSA2");
            AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
          //异步接收地址,仅支持http/https,公网可访问
          // request.setNotifyUrl("");
          //同步跳转地址,仅支持http/https
          // request.setReturnUrl("");
          /******必传参数******/
            JSONObject bizContent = new JSONObject();
          //商户订单号,商家自定义,保持唯一性
            bizContent.put("out_trade_no", orderInfo.getOrderNo());
          //支付金额,最小值0.01元
            BigDecimal total = new BigDecimal(orderInfo.getTotalFee().toString()).divide(new BigDecimal("100"));
            bizContent.put("total_amount", total);
          //订单标题,不可使用特殊符号
            bizContent.put("subject", orderInfo.getTitle());
          //电脑网站支付场景固定传值FAST_INSTANT_TRADE_PAY
            bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
            
            request.setBizContent(bizContent.toString());

            AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
          // 如果需要返回GET请求,请使用
          // AlipayTradePagePayResponse response = alipayClient.pageExecute(request,"GET");

            if(response.isSuccess()){
                log.info("调用成功,返回结果 ===> "+ response.getBody());
                return response.getBody();
            } else {
                log.info("调用失败,返回码 ===> "+ response.getCode()+",返回描述 ===> "+response.getMsg());
                throw new RuntimeException("创建支付交易失败");
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new RuntimeException("创建支付交易失败");
        }

    }
}
(5). OrderInfoServiceImpl实现类代码(有关订单信息的一些方法)
@Service
@Slf4j
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Resource
    private ProductMapper productMapper;


    @Override
    public OrderInfo createOrderByProductId(Long productId) {

        //查找已存在但未支付的订单
        OrderInfo orderInfo = this.getNoPayOrderByProductId(productId);
        if( orderInfo != null){
            return orderInfo;
        }

        //获取商品信息
        Product product = productMapper.selectById(productId);

        //生成订单
        orderInfo = new OrderInfo();
        orderInfo.setTitle(product.getTitle());
        orderInfo.setOrderNo(OrderNoUtils.getOrderNo()); //订单号
        orderInfo.setProductId(productId);
        orderInfo.setTotalFee(product.getPrice()); //分
        orderInfo.setOrderStatus(OrderStatus.NOTPAY.getType());
        baseMapper.insert(orderInfo);

        return orderInfo;
    }

    /**
     * 存储订单二维码
     * @param orderNo
     * @param codeUrl
     */
    @Override
    public void saveCodeUrl(String orderNo, String codeUrl) {

        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_no", orderNo);

        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setCodeUrl(codeUrl);

        baseMapper.update(orderInfo, queryWrapper);
    }

    /**
     * 查询订单列表,并倒序查询
     * @return
     */
    @Override
    public List<OrderInfo> listOrderByCreateTimeDesc() {

        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<OrderInfo>().orderByDesc("create_time");
        return baseMapper.selectList(queryWrapper);
    }

    /**
     * 根据订单号更新订单状态
     * @param orderNo
     * @param orderStatus
     */
    @Override
    public void updateStatusByOrderNo(String orderNo, OrderStatus orderStatus) {

        log.info("更新订单状态 ===> {}", orderStatus.getType());

        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_no", orderNo);

        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setOrderStatus(orderStatus.getType());

        baseMapper.update(orderInfo, queryWrapper);
    }

    /**
     * 根据订单号获取订单状态
     * @param orderNo
     * @return
     */
    @Override
    public String getOrderStatus(String orderNo) {

        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_no", orderNo);
        OrderInfo orderInfo = baseMapper.selectOne(queryWrapper);
        if(orderInfo == null){
            return null;
        }
        return orderInfo.getOrderStatus();
    }

    /**
     * 查询创建超过minutes分钟并且未支付的订单
     * @param minutes
     * @return
     */
    @Override
    public List<OrderInfo> getNoPayOrderByDuration(int minutes) {

        Instant instant = Instant.now().minus(Duration.ofMinutes(minutes));

        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_status", OrderStatus.NOTPAY.getType());
        queryWrapper.le("create_time", instant);

        List<OrderInfo> orderInfoList = baseMapper.selectList(queryWrapper);

        return orderInfoList;
    }

    /**
     * 根据订单号获取订单
     * @param orderNo
     * @return
     */
    @Override
    public OrderInfo getOrderByOrderNo(String orderNo) {

        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_no", orderNo);
        OrderInfo orderInfo = baseMapper.selectOne(queryWrapper);

        return orderInfo;
    }


    /**
     * 根据商品id查询未支付订单
     * 防止重复创建订单对象
     * @param productId
     * @return
     */
    private OrderInfo getNoPayOrderByProductId(Long productId) {

        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("product_id", productId);
        queryWrapper.eq("order_status", OrderStatus.NOTPAY.getType());
//        queryWrapper.eq("user_id", userId);
        OrderInfo orderInfo = baseMapper.selectOne(queryWrapper);
        return orderInfo;
    }
}
(6). 订单表(OrderInfo)和商品表(Product)的实体类代码
@Data
public class OrderInfo  extends BaseEntity{

    private String title;//订单标题

    private String orderNo;//商户订单编号

    private Long userId;//用户id

    private Long productId;//支付产品id

    private Integer totalFee;//订单金额(分)

    private String codeUrl;//订单二维码连接

    private String orderStatus;//订单状态
}
@Data
public class Product extends BaseEntity{

    private String title; //商品名称

    private Integer price; //价格(分)
}
(7). 创建的OrderInfoController和ProductController
@CrossOrigin //开放前端的跨域访问
@Api(tags = "商品订单管理")
@RestController
@RequestMapping("/api/order-info")
public class OrderInfoController {

    @Resource
    private OrderInfoService orderInfoService;

    @ApiOperation("订单列表")
    @GetMapping("/list")
    public R list(){

        List<OrderInfo> list = orderInfoService.listOrderByCreateTimeDesc();
        return R.ok().data("list", list);
    }

    /**
     * 查询本地订单状态
     * @param orderNo
     * @return
     */
    @ApiOperation("查询本地订单状态")
    @GetMapping("/query-order-status/{orderNo}")
    public R queryOrderStatus(@PathVariable String orderNo){
        String orderStatus = orderInfoService.getOrderStatus(orderNo);
        if(OrderStatus.SUCCESS.getType().equals(orderStatus)){
            return R.ok().setMessage("支付成功"); //支付成功
        }
        return R.ok().setCode(101).setMessage("支付中......");
    }

}
@CrossOrigin //开放前端的跨域访问
@Api(tags = "商品管理")
@RestController
@RequestMapping("/api/product")
public class ProductController {

    @Resource
    private ProductService productService;

    @ApiOperation("商品列表")
    @GetMapping("/list")
    public R list(){
        List<Product> list = productService.list();
        return R.ok().data("productList", list);
    }

}
(8). 其他类
public class OrderNoUtils {

    /**
     * 获取订单编号
     * @return
     */
    public static String getOrderNo() {
        return "ORDER_" + getNo();
    }

    /**
     * 获取退款单编号
     * @return
     */
    public static String getRefundNo() {
        return "REFUND_" + getNo();
    }

    /**
     * 获取编号
     * @return
     */
    public static String getNo() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String newDate = sdf.format(new Date());
        String result = "";
        Random random = new Random();
        for (int i = 0; i < 3; i++) {
            result += random.nextInt(10);
        }
        return newDate + result;
    }

}

(9). 最后在启动类上加上@EnableScheduling注解,启动便可成功

(10).前端页面只需要写一个js就行了,它会自己有一个页面,通过浏览器解析写入就行了

//productId要自己在前面获取定义,然后直接在购买按钮是调用toPay就行
function toPay() {
        //调用支付宝统一收单下单并支付页面接口
        fetch(`/api/ali-pay/trade/page/pay/${productId}`,{
            method: 'POST',
            headers: {
                'Content-Type': 'text/html;charset=UTF-8'
            }
        })
            .then(response => response.json())
            .then(response =>{
                //将支付宝返回的表单字符串写在浏览器中,表单会自动触发submit提交
                alert(response.data)
                document.write(response.data)
            })
    }

注意: 如果报错,把数据库订单信息表里的数据删了再试一试

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!关于SSM框架下支付宝沙箱支付教程,我可以为你提供一些基本的步骤和指导。首先,你需要在支付宝开放平台申请一个开发者账号,并创建一个沙箱环境的应用。 下面是大致的步骤: 1. 在支付宝开放平台(https://open.alipay.com)上注册一个账号,并登录进入开发者控制台。 2. 创建一个应用,选择沙箱环境。 3. 在应用详情页中,获取应用的App ID、签名类型以及支付宝公钥和私钥。 4. 在SSM项目中添加支付宝SDK的依赖。你可以在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>com.alipay.sdk</groupId> <artifactId>alipay-sdk-java</artifactId> <version>4.9.9.ALL</version> </dependency> ``` 5. 编写支付宝支付的配置类,可以参考以下代码: ```java @Configuration public class AlipayConfig { @Value("${alipay.appId}") private String appId; @Value("${alipay.privateKey}") private String privateKey; @Value("${alipay.publicKey}") private String publicKey; @Value("${alipay.serverUrl}") private String serverUrl; @Value("${alipay.format}") private String format; @Value("${alipay.charset}") private String charset; @Value("${alipay.signType}") private String signType; @Bean public AlipayClient alipayClient() { return new DefaultAlipayClient(serverUrl, appId, privateKey, format, charset, publicKey, signType); } } ``` 6. 编写支付请求的接口和Controller,可以参考以下代码: ```java @RestController @RequestMapping("/pay") public class PayController { @Autowired private AlipayClient alipayClient; @PostMapping("/create") public String createPayOrder() throws AlipayApiException { AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest(); //设置支付宝回调地址 request.setNotifyUrl("http://your-domain.com/notify"); //设置支付请求参数 //... String form = alipayClient.pageExecute(request).getBody(); return form; } } ``` 这里只是一个简单的示例,你需要根据你的具体需求进行相应的配置和参数设置。 希望以上信息对你有帮助!如果有任何问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值