整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

微软:Win 11 商店将 HTML 替换为 XAML,性能得到显著提升

T之家 7 月 4 日消息 随着首个 Win11 预览版的发布,全新的微软商店现已上线,并将在今年晚些时候开始向主流用户推出。

在 6 月 24 日的发布会上,微软表示 Windows 11 商店已经经过了“从头到脚重新设计”。整个界面都进行了更新,滚动速度更快,还为更多内容增加了空间。据微软官方称,用户操作更简单,HTML 组件也已经被砍掉了。

在 Windows 10 上,微软商店的前端部分构建于 HTML/CSS (web 组件) 中。例如产品页面完全基于 html,虽然兼容性高一点但这大大降低了用户体验,尤其是当用户点击“获取”或“安装”按钮时还会崩溃。

例如,之前有网友反馈称下载大文件时大概率会失败,而且错误代码还没有给出任何解释。

在 Windows 11 中,微软将用 XAML/c# 语言编写的全新商店取代现有的商店,据微软官方员称,它是完全“UWP”的。

据称,新版应用商店的性能得到了显著改善,例如下载不再出现之前出现的中、大型应用和游戏的下载失败问题。一些不愿透露姓名的消息人士也证实,用户在新版商店中下载大型游戏的速度也变得更快。

Microsoft Store 店商业模式的巨大改变

通过 Windows 11,微软也在尝试改变其 Microsoft Store 的商业模式。

该公司希望所有开发者都去尽可能为 Microsoft Store 开发应用程序和游戏,而开发者现可使用自己的第三方商业支付系统,相对来说更加宽容和自由。

IT之家了解到,微软还支持通过添加更多使用不同框架创建的应用和游戏来扩展 Store 目录。微软 Teams 和 Visual Studio 预计将在今年年底上线全新商店。

值得一提的是,Adobe, Zoom, OBS Studio 和 Canva 等著名应用现已上架微软新版 Microsoft Store。

此外,Windows Insider 体验者可以通过使用旧版商店手动更新来下载新设计的 Microsoft Store。当然,虽然商店已经经过重新设计,但一些功能,如通过亚马逊应用商店 整合 Android 应用的功能仍未上线。

微软还表示,Windows 10 用户将在今年晚些时候获得相同的商店体验,其商店的质量将在未来几个月得到显著提高,例如搜索结果将不再包括低质量的指南/教程等内容。

:简介

电脑支付常用于电商和后台管理系统的账户充值等场景。

电脑网站支付 文档

电脑网站支付流程图

二:集成步骤

0. 创建应用、配置密钥

集成前需要先创建应用、配置密钥、回调地址等以及alipay-sdk-java.jar和alipay-trade-sdk.jar请查看Spring Boot入门教程(三十五):支付宝集成-准备工作

1. dependency

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <!-- alipay begin -->
    <dependency>
        <groupId>com.alipay</groupId>
        <artifactId>alipay-sdk-java</artifactId>
        <version>20170725114550</version>
    </dependency>
    <dependency>
        <groupId>com.alipay</groupId>
        <artifactId>alipay-trade-sdk</artifactId>
        <version>20161215</version>
    </dependency>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
    </dependency>
    <dependency>
        <groupId>commons-configuration</groupId>
        <artifactId>commons-configuration</artifactId>
        <version>1.10</version>
    </dependency>
    <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>core</artifactId>
        <version>3.2.1</version>
    </dependency>
    <!-- alipay end -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

2. application.yml

# 沙箱账号
pay:
  alipay:
    gatewayUrl: https://openapi.alipaydev.com/gateway.do
    appid: 2016091400508498
    appPrivateKey: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCtXKWs+trRSuCxEUvlsEeSAuLWs3B/Dh74R8223BnfzoA29aGeoycAqfKlBMcbzU2G1KayESvZKGpwBLeejSbecRYjgZsQDyEaDimQQJtGFvZVV6u4XNnvIJ72eQzEaEIQfuiorjBTLm6DQuds4R0GxftqON6QFoIZkWB9ZrZKd02cuy16dW+UqtLVGGAHcCIAkB63zUiKSNfweMddneZ7MVs3lvu3xhMnD+5us/+n2Vp4qhfmpYLcdqIW6InU4GypeoOpyUTrfUGpgdR0l924vHy/GQJZEKFaRcK3cYK+ECyKpSIoqaJJFLHbkqsliuPpMUG+rM3jiqeIAH4psAznAgMBAAECggEBAJ5jyEbbxrJzrAh7GhHX1fwUQPYSadTbrPYAfHX2cHlnrQMJtsk+nTLhEv0r+VJwZ8WpYkfMong8kcqYtL7ajcmsHqMAFhE9EWxBxj2ymWsXLabZe93sj30IG9Rq0nxcGQgDO0RqKWLGSFgK93Al2KRInKT3InkY53K+vR61ihVLmGf7+GwPtIZteBy+tuAyvcj2RlkYvjiFi3ySyZ1wA3sJIlgrGiixd6fj20XFGNE3CnAwu0BJgXXbP/S9J4C0RRa3ZXj8fX7oONhVxz2xKxn7AT4e8OWjt7J41H2LRct8Fgl9pqgz2FJYv/WfbkG8x9fGiKYYvPXoxjjrk/tkewkCgYEA8f9Lcu5JPrE9rpw9zlwhm5cOO81xLxdwL5R5/1bRP48BZGIYuqlCbVvjJVqtO8eTnLhUwH7fG8B7cmoeO9bGr9GQrtfyCqz6FtVymTBieJlfgZDVhtzyv2qKOBMIFE8jsbSBK/NHHMvykJ+XdQ1riwCeQDdXICRuYTTFwGk2OsUCgYEAt2SoN95tVmVrvKG6ATLNEtge/ozeVywA4GjltrSw/G9vqp+DkkT2pY19uROuzMazoTzKWpPho2q/qzNlv/ANbOFM2GEmKamQ7CO88JgRxMsPTvc/HxCLU/ClMJU8LcOf9LfP2KYZpPwuheKJoF4vDGj8NsbFmccJyYSdpkNEk7sCgYBJlL2FMaz1sgC2Ue19DIhvfaunRV1P20mSPgwmNmijccETm7w3LXX0OIdFeV/JGHLqqSWj7i+6iXk/ncKZoUGCfi8G6sQ+uL/GJ5qTt6GJV+ExTS+PtSjeSO/EAw1m13Vb+C16hpstx1l23f+4aJ81gbecgPct38XsKpaiXZtOnQKBgQCMsN7QRYYxwoq9YoDUzIlAzKYyeBVWYL6najHYUZR5hG/xQIBqZRem9/4cTvpJxKInrwA6LrrqaEl0aHDFp75U6h7O3PCvA5PXZK9dD/yJsZIj7U/yX/nTQokn1UUegrYiwiTkusBvrrtuINWePsLvTVc4GpObHnPmsiNTWsWwYwKBgENaeTNOCHV2km/ysXQSEIhKbtlAMQPsgWHCt/bzHlF9m18izb1LrJyjzcSsd+Zy78R+pv4G50Q27c3e/DFPz/wYxN/yHWRbyLBA8ipJbCtMtPEdS9krpmN6cChIdLGbz4CVUqOPSRzNb9lhhgPCcCNRq6DG3HBceb1Se9VnO3zk
    alipayPublicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApFQKccMq+wPoWh93DcX3XYrnT7FJ3gntJA/jEwgk6Jd3iEVS2CyUCCgFVcQn8xjXT81YbZHYvoC50IBuu+A+Ey+J8VIgsBm5g9uwbOLRf66GrZjuKOlalHm5gHXjcL2gZRMBJEStOxstcO2YQriqhQzdL3EKp+HQc9u14IOVFpZdR8qq1l7CzKHn1vQo/1fUPfUrTLQqSuQTU9Ospv/QHFqOJA7DPetUQ+jnaZ082f3clr4ITw4EE8A6IWqTXcETTx5j/udCGP84g2Y4j+8i9DqYGyD5ePVgt4G0ICBX1bi1qNlylfxRg8Y3c1DFrRGyr0NpKQxSVXkYaVNvrCoudQIDAQAB
    returnUrl: http://s9v2cw.natappfree.cc/alipay/return
    notifyUrl: http://s9v2cw.natappfree.cc/alipay/notify

spring:
  thymeleaf:
    prefix: classpath:/templates/
    suffix: .html
    mode: HTML5
    encoding: UTF-8

3. AlipayProperties

/**
 * 支付宝支付的参数配置
 *
 * @author mengday zhang
 */
@Data
@Slf4j
@ConfigurationProperties(prefix = "pay.alipay")
public class AlipayProperties {

    /** 支付宝gatewayUrl */
    private String gatewayUrl;
    /** 商户应用id */
    private String appid;
    /** RSA私钥,用于对商户请求报文加签 */
    private String appPrivateKey;
    /** 支付宝RSA公钥,用于验签支付宝应答 */
    private String alipayPublicKey;
    /** 签名类型 */
    private String signType = "RSA2";

    /** 格式 */
    private String formate = "json";
    /** 编码 */
    private String charset = "UTF-8";

    /** 同步地址 */
    private String returnUrl;

    /** 异步地址 */
    private String notifyUrl;

    /** 最大查询次数 */
    private static int maxQueryRetry = 5;
    /** 查询间隔(毫秒) */
    private static long queryDuration = 5000;
    /** 最大撤销次数 */
    private static int maxCancelRetry = 3;
    /** 撤销间隔(毫秒) */
    private static long cancelDuration = 3000;

    private AlipayProperties() {}

    /**
     * PostContruct是spring框架的注解,在方法上加该注解会在项目启动的时候执行该方法,也可以理解为在spring容器初始化的时候执行该方法。
     */
    @PostConstruct
    public void init() {
        log.info(description());
    }

    public String description() {
        StringBuilder sb = new StringBuilder("\nConfigs{");
        sb.append("支付宝网关: ").append(gatewayUrl).append("\n");
        sb.append(", appid: ").append(appid).append("\n");
        sb.append(", 商户RSA私钥: ").append(getKeyDescription(appPrivateKey)).append("\n");
        sb.append(", 支付宝RSA公钥: ").append(getKeyDescription(alipayPublicKey)).append("\n");
        sb.append(", 签名类型: ").append(signType).append("\n");

        sb.append(", 查询重试次数: ").append(maxQueryRetry).append("\n");
        sb.append(", 查询间隔(毫秒): ").append(queryDuration).append("\n");
        sb.append(", 撤销尝试次数: ").append(maxCancelRetry).append("\n");
        sb.append(", 撤销重试间隔(毫秒): ").append(cancelDuration).append("\n");
        sb.append("}");
        return sb.toString();
    }

    private String getKeyDescription(String key) {
        int showLength = 6;
        if (StringUtils.isNotEmpty(key) && key.length() > showLength) {
            return new StringBuilder(key.substring(0, showLength)).append("******")
                    .append(key.substring(key.length() - showLength)).toString();
        }
        return null;
    }
}

4. AlipayConfiguration

/**
 * 两个支付宝客户端,用户可以使用任意一个.
 *
 * alipay-trade-sdk 是对alipay-sdk-java的封装,建议使用alipay-trade-sdk.
 *
 * @author mengday zhang
 */
@Configuration
@EnableConfigurationProperties(AlipayProperties.class)
public class AlipayConfiguration {

    @Autowired
    private AlipayProperties properties;

    /**
     * alipay-trade-sdk
     * @return
     */
    @Bean
    public AlipayTradeService alipayTradeService() {
        return new AlipayTradeServiceImpl.ClientBuilder()
                .setGatewayUrl(properties.getGatewayUrl())
                .setAppid(properties.getAppid())
                .setPrivateKey(properties.getAppPrivateKey())
                .setAlipayPublicKey(properties.getAlipayPublicKey())
                .setSignType(properties.getSignType())
                .build();
    }

    /**
     * alipay-sdk-java
     * @return
     */
    @Bean
    public AlipayClient alipayClient(){
        return new DefaultAlipayClient(properties.getGatewayUrl(),
                properties.getAppid(),
                properties.getAppPrivateKey(),
                properties.getFormate(),
                properties.getCharset(),
                properties.getAlipayPublicKey(),
                properties.getSignType());
    }
}

5. AlipayPagePayController

/**
 * 支付宝-电脑网站支付.
 * <p>
 * 电脑网站支付 https://docs.open.alipay.com/270/105898/
 *
 * @author Mengday Zhang
 * @version 1.0
 * @since 2018/6/14
 */
@Controller
@RequestMapping("/alipay/page")
public class AlipayPagePayController {

    @Autowired
    private AlipayProperties alipayProperties;

    @Autowired
    private AlipayClient alipayClient;

    @Autowired
    private AlipayController alipayController;


    @PostMapping("/gotoPayPage")
    public void gotoPayPage(HttpServletResponse response) throws AlipayApiException, IOException {
        // 订单模型
        String productCode = "FAST_INSTANT_TRADE_PAY";
        AlipayTradePagePayModel model = new AlipayTradePagePayModel();
        model.setOutTradeNo(UUID.randomUUID().toString());
        model.setSubject("支付测试");
        model.setTotalAmount("0.01");
        model.setBody("支付测试,共0.01元");
        model.setProductCode(productCode);

        AlipayTradePagePayRequest pagePayRequest =new AlipayTradePagePayRequest();
        pagePayRequest.setReturnUrl("http://s9v2cw.natappfree.cc/alipay/page/returnUrl");
        pagePayRequest.setNotifyUrl(alipayProperties.getNotifyUrl());
        pagePayRequest.setBizModel(model);

        // 调用SDK生成表单, 并直接将完整的表单html输出到页面
        String form = alipayClient.pageExecute(pagePayRequest).getBody();
        response.setContentType("text/html;charset=" + alipayProperties.getCharset());
        response.getWriter().write(form);
        response.getWriter().flush();
        response.getWriter().close();
    }

    @RequestMapping("/returnUrl")
    public String returnUrl(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException, AlipayApiException {
        response.setContentType("text/html;charset=" + alipayProperties.getCharset());

        boolean verifyResult = alipayController.rsaCheckV1(request);
        if(verifyResult){
            //验证成功
            //请在这里加上商户的业务逻辑程序代码,如保存支付宝交易号
            //商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
            //支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");

            return "pagePaySuccess";

        }else{
            return "pagePayFail";

        }
    }
}

6. AlipayController

/**
 * 支付宝通用接口.
 * <p>
 * detailed description
 *
 * @author Mengday Zhang
 * @version 1.0
 * @since 2018/6/13
 */
@Slf4j
@RestController
@RequestMapping("/alipay")
public class AlipayController {

    @Autowired
    private AlipayProperties aliPayProperties;

    @Autowired
    private AlipayClient alipayClient;

    @Autowired
    private AlipayTradeService alipayTradeService;

    /**
     * 支付异步通知
     *
     * 接收到异步通知并验签通过后,一定要检查通知内容,包括通知中的app_id、out_trade_no、total_amount是否与请求中的一致,并根据trade_status进行后续业务处理。
     *
     * https://docs.open.alipay.com/194/103296
     */
    @RequestMapping("/notify")
    public String notify(HttpServletRequest request) throws AlipayApiException, UnsupportedEncodingException {
        // 一定要验签,防止黑客篡改参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        StringBuilder notifyBuild = new StringBuilder("/****************************** alipay notify ******************************/\n");
        parameterMap.forEach((key, value) -> notifyBuild.append(key + "=" + value[0] + "\n") );
        log.info(notifyBuild.toString());


        boolean flag = this.rsaCheckV1(request);
        if (flag) {
            /**
             * TODO 需要严格按照如下描述校验通知数据的正确性
             *
             * 商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
             * 并判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
             * 同时需要校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email),
             *
             * 上述有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。
             * 在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。
             * 在支付宝的业务通知中,只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功。
             */

            //交易状态
            String tradeStatus = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");
            // 商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
            //支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
            //付款金额
            String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8");
            // TRADE_FINISHED(表示交易已经成功结束,并不能再对该交易做后续操作);
            // TRADE_SUCCESS(表示交易已经成功结束,可以对该交易做后续操作,如:分润、退款等);
            if(tradeStatus.equals("TRADE_FINISHED")){
                //判断该笔订单是否在商户网站中已经做过处理
                //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,
                // 并判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),并执行商户的业务程序
                //请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
                //如果有做过处理,不执行商户的业务程序

                //注意:
                //如果签约的是可退款协议,退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
                //如果没有签约可退款协议,那么付款完成后,支付宝系统发送该交易状态通知。
            } else if (tradeStatus.equals("TRADE_SUCCESS")){
                //判断该笔订单是否在商户网站中已经做过处理
                //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,
                // 并判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),并执行商户的业务程序
                //请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
                //如果有做过处理,不执行商户的业务程序

                //注意:
                //如果签约的是可退款协议,那么付款完成后,支付宝系统发送该交易状态通知。

            }

            return "success";
        }

        return "fail";
    }

    /**
     * 订单查询(最主要用于查询订单的支付状态)
     * @param orderNo 商户订单号
     * @return
     */
    @GetMapping("/query")
    public String query(String orderNo){

        AlipayTradeQueryRequestBuilder builder = new AlipayTradeQueryRequestBuilder()
                .setOutTradeNo(orderNo);
        AlipayF2FQueryResult result = alipayTradeService.queryTradeResult(builder);
        switch (result.getTradeStatus()) {
            case SUCCESS:
                log.info("查询返回该订单支付成功: )");

                AlipayTradeQueryResponse resp = result.getResponse();
                log.info(resp.getTradeStatus());
//                log.info(resp.getFundBillList());
                break;

            case FAILED:
                log.error("查询返回该订单支付失败!!!");
                break;

            case UNKNOWN:
                log.error("系统异常,订单支付状态未知!!!");
                break;

            default:
                log.error("不支持的交易状态,交易返回异常!!!");
                break;
        }
        return result.getResponse().getBody();
    }

    /**
     * 退款
     * @param orderNo 商户订单号
     * @return
     */
    @PostMapping("/refund")
    @ResponseBody
    public String refund(String orderNo) throws AlipayApiException {
        AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest();

        AlipayTradeRefundModel model=new AlipayTradeRefundModel();
        // 商户订单号
        model.setOutTradeNo(orderNo);
        // 退款金额
        model.setRefundAmount("0.01");
        // 退款原因
        model.setRefundReason("无理由退货");
        // 退款订单号(同一个订单可以分多次部分退款,当分多次时必传)
//        model.setOutRequestNo(UUID.randomUUID().toString());
        alipayRequest.setBizModel(model);

        AlipayTradeRefundResponse alipayResponse = alipayClient.execute(alipayRequest);
        System.out.println(alipayResponse.getBody());

        return alipayResponse.getBody();
    }

    /**
     * 退款查询
     * @param orderNo 商户订单号
     * @param refundOrderNo 请求退款接口时,传入的退款请求号,如果在退款请求时未传入,则该值为创建交易时的外部订单号
     * @return
     * @throws AlipayApiException
     */
    @GetMapping("/refundQuery")
    @ResponseBody
    public String refundQuery(String orderNo, String refundOrderNo) throws AlipayApiException {
        AlipayTradeFastpayRefundQueryRequest alipayRequest = new AlipayTradeFastpayRefundQueryRequest();

        AlipayTradeFastpayRefundQueryModel model=new AlipayTradeFastpayRefundQueryModel();
        model.setOutTradeNo(orderNo);
        model.setOutRequestNo(refundOrderNo);
        alipayRequest.setBizModel(model);

        AlipayTradeFastpayRefundQueryResponse alipayResponse = alipayClient.execute(alipayRequest);
        System.out.println(alipayResponse.getBody());

        return alipayResponse.getBody();
    }

    /**
     * 关闭交易
     * @param orderNo
     * @return
     * @throws AlipayApiException
     */
    @PostMapping("/close")
    @ResponseBody
    public String close(String orderNo) throws AlipayApiException {
        AlipayTradeCloseRequest alipayRequest = new AlipayTradeCloseRequest();
        AlipayTradeCloseModel model =new AlipayTradeCloseModel();
        model.setOutTradeNo(orderNo);
        alipayRequest.setBizModel(model);

        AlipayTradeCloseResponse alipayResponse = alipayClient.execute(alipayRequest);
        System.out.println(alipayResponse.getBody());

        return alipayResponse.getBody();
    }

    /**
     * 校验签名
     * @param request
     * @return
     */
    public boolean rsaCheckV1(HttpServletRequest request){
        // https://docs.open.alipay.com/54/106370
        // 获取支付宝POST过来反馈信息
        Map<String,String> params = new HashMap<>();
        Map requestParams = request.getParameterMap();
        for (Iterator 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);
        }

        try {
            boolean verifyResult = AlipaySignature.rsaCheckV1(params,
                    aliPayProperties.getAlipayPublicKey(),
                    aliPayProperties.getCharset(),
                    aliPayProperties.getSignType());

            return verifyResult;
        } catch (AlipayApiException e) {
            log.debug("verify sigin error, exception is:{}", e);
            return false;
        }
    }
}

7. WebMvcConfiguration

/**
 * WebMVC 配置.
 * <p>
 * 添加路径和页面的映射关系
 *
 * @author Mengday Zhang
 * @version 1.0
 * @since 2018/6/13
 */
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
    @Override
    protected void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/gotoWapPage").setViewName("gotoWapPay");
        registry.addViewController("/gotoPagePage").setViewName("gotoPagePay");
        super.addViewControllers(registry);
    }
}

8. templates

gotoPagePay.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body style="font-size: 30px">

<form method="post" action="/alipay/page/gotoPayPage">
    <h3>购买商品:越南新娘</h3>
    <h3>价格:20000</h3>
    <h3>数量:10个</h3>

    <button style="width: 100%; height: 60px; alignment: center; background: #b49e8f" type="submit">立即支付</button>
</form>

</body>
</html>

pagePaySuccess.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>电脑网站支付 成功,我们将尽快从越南偷渡过来,收货后请请及时验货!欢迎下次再来</h1>

</body>
</html>

三:Demo图

三:查询对账单下载地址

本教程详细介绍了如何使用ssm框架实现支付宝支付功能。本文章分为两大部分,分别是「支付宝测试环境代码测试」和「将支付宝支付整合到ssm框架」,详细的代码和图文解释,自己实践的时候一定仔细阅读相关文档,话不多说我们开始。

一、支付宝测试环境代码测试


源代码

https://github.com/OUYANGSIHAI/sihai-maven-ssm-alipay

1、下载电脑网站的官方demo:

下载:https://docs.open.alipay.com/270/106291/

2.下载解压导入eclipse

readme.txt请好好看一下。

只有一个Java配置类,其余都是JSP。

3、配置AlipayConfig

(1) 注册蚂蚁金服开发者账号(免费,不像苹果会收取费用)

注册地址:https://open.alipay.com ,用你的支付宝账号扫码登录,完善个人信息,选择服务类型(我选的是自研)。

(2) 设置app_id和gatewayUrl

其中密钥需要自己生成,appID和支付宝网关是已经给好的,网关有dev字样,表明是用于开发测试。

(3) 设置密钥

点击“生成方法”,打开界面如下:

下周密钥生成工具,解压打开后,选择2048位生成密钥:

如果没有设置过,此时显示文本是"设置应用公钥",我这里是已经设置过得。

设置方法,"打开密钥文件路径":

复制应用公钥2048.txt中的内容到点击"设置应用公钥"的弹出框中,保存:

  • 商户私钥(merchant_private_key)复制 应用私钥2048.txt 中的内容到merchant_private_key中。
  • 支付宝公钥(alipay_public_key)

点击如上图链接,复制弹出框里面的内容到alipay_public_key。

如果这个设置不对,结果是:支付成功,但是验签失败。

如果是正式环境,需要上传到对应的应用中:

(4) 服务器异步通知页面路径(notify_url)

如果没有改名,修改IP和端口号就可以了,我自己的如下:

http://localhost:8080/alipay.trade.page.pay-JAVA-UTF-8/notify_url.jsp

(5) 页面跳转同步通知页面的路径(return_url)

http://localhost:8080/alipay.trade.page.pay-JAVA-UTF-8/return_url.jsp

4、测试运行

测试用的支付宝买家账户可以在"沙箱账"这个页面可以找到:

支付成功后,验签结果:

问题解决

由于我们使用的是沙箱测试环境,测试环境和正式上线的环境的网关是不一样的,如果配置错误,会出现,appid错误的问题。配置如下:

源代码下载

链接: https://pan.baidu.com/s/1n6GbEJiMzoGWJrSw0bb2Cg 密码: zd9e

二、将支付宝支付整合到ssm框架

1、项目架构

  • 项目架构:spring+springmvc+mybatis
  • 数据库:mysql
  • 部署环境:tomcat9.0
  • 开发环境:jdk9、idea
  • 支付:支付宝、微信

整合到ssm一样,我们需要像沙箱测试环境一样,需要修改支付的配置信息

2、数据库代码

主要包括以下的数据库表:

  • user:用户表
  • order:支付产生的订单
  • flow:流水账
  • product:商品表:用于模拟购买商品。
drop table if exists user;

/*==============================================================*/
/* Table: user */
/*==============================================================*/
create table user
(
 id varchar(20) not null,
 username varchar(128),
 sex varchar(20),
 primary key (id)
);

alter table user comment '用户表';


CREATE TABLE `flow` (
 `id` varchar(20) NOT NULL,
 `flow_num` varchar(20) DEFAULT NULL COMMENT '流水号',
 `order_num` varchar(20) DEFAULT NULL COMMENT '订单号',
 `product_id` varchar(20) DEFAULT NULL COMMENT '产品主键ID',
 `paid_amount` varchar(11) DEFAULT NULL COMMENT '支付金额',
 `paid_method` int(11) DEFAULT NULL COMMENT '支付方式
 1:支付宝
 2:微信',
 `buy_counts` int(11) DEFAULT NULL COMMENT '购买个数',
 `create_time` datetime DEFAULT NULL COMMENT '创建时间',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='流水表';


CREATE TABLE `orders` (
 `id` varchar(20) NOT NULL,
 `order_num` varchar(20) DEFAULT NULL COMMENT '订单号',
 `order_status` varchar(20) DEFAULT NULL COMMENT '订单状态
 10:待付款
 20:已付款',
 `order_amount` varchar(11) DEFAULT NULL COMMENT '订单金额',
 `paid_amount` varchar(11) DEFAULT NULL COMMENT '实际支付金额',
 `product_id` varchar(20) DEFAULT NULL COMMENT '产品表外键ID',
 `buy_counts` int(11) DEFAULT NULL COMMENT '产品购买的个数',
 `create_time` datetime DEFAULT NULL COMMENT '订单创建时间',
 `paid_time` datetime DEFAULT NULL COMMENT '支付时间',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';


CREATE TABLE `product` (
 `id` varchar(20) NOT NULL,
 `name` varchar(20) DEFAULT NULL COMMENT '产品名称',
 `price` varchar(11) DEFAULT NULL COMMENT '价格',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='产品表 ';

3、dao数据接口层

这里就不介绍了,这个只包括简单的curd,可以使用`通用mapper`,或者`逆向工程`就行。以订单order为例给出:

public interface OrdersMapper {
 int countByExample(OrdersExample example);

 int deleteByExample(OrdersExample example);

 int deleteByPrimaryKey(String id);

 int insert(Orders record);

 int insertSelective(Orders record);

 List<Orders> selectByExample(OrdersExample example);

 Orders selectByPrimaryKey(String id);

 int updateByExampleSelective(@Param("record") Orders record, @Param("example") OrdersExample example);

 int updateByExample(@Param("record") Orders record, @Param("example") OrdersExample example);

 int updateByPrimaryKeySelective(Orders record);

 int updateByPrimaryKey(Orders record);
}

注意:源代码最后给出

4、service层

同上,最后在项目源代码里可见。以订单order为例给出:

/**
 * 订单操作 service
 * @author ibm
 *
 */
public interface OrdersService {

 /**
 * 新增订单
 * @param order
 */
 public void saveOrder(Orders order);

 /**
 * 
 * @Title: OrdersService.java
 * @Package com.sihai.service
 * @Description: 修改叮当状态,改为 支付成功,已付款; 同时新增支付流水
 * Copyright: Copyright (c) 2017
 * Company:FURUIBOKE.SCIENCE.AND.TECHNOLOGY
 * 
 * @author sihai
 * @date 2017年8月23日 下午9:04:35
 * @version V1.0
 */
 public void updateOrderStatus(String orderId, String alpayFlowNum, String paidAmount);

 /**
 * 获取订单
 * @param orderId
 * @return
 */
 public Orders getOrderById(String orderId);

}

三、支付宝支付controller(支付流程)

支付流程图

首先,启动项目后,输入http://localhost:8080/,会进入到商品页面,如下:

下面是页面代码

商品页面(products.jsp)

代码实现:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %> 
<script src="<%=request.getContextPath() %>/static/js/jquery.min.js" type="text/javascript"></script>

<html>

 <head>

 </head>

 <body>

 <table>
 <tr>
 <td>
 产品编号
 </td>
 <td>
 产品名称
 </td>
 <td>
 产品价格
 </td>
 <td>
 操作
 </td>
 </tr>
 <c:forEach items="${pList }" var="p">
 <tr>
 <td>
 ${p.id }
 </td>
 <td>
 ${p.name }
 </td>
 <td>
 ${p.price }
 </td>
 <td>
 <a href="<%=request.getContextPath() %>/alipay/goConfirm.action?productId=${p.id }">购买</a>
 </td>
 </tr>

 </c:forEach>
 </table>

 <input type="hidden" id="hdnContextPath" name="hdnContextPath" value="<%=request.getContextPath() %>"/>
 </body>

</html>


<script type="text/javascript">

 $(document).ready(function() {

 var hdnContextPath = $("#hdnContextPath").val();


 });


</script>

点击上面的购买,进入到订单页面

填写个数,然后点击生成订单,调用如下代码

根据SID(生成id的工具)等信息生成订单,保存到数据库。

进入到选择支付页面

调用了如下代码:

然后,我们选择支付宝支付,进入到了我们支付的页面了,大功告成!

调用了如下代码:

/**
 *
 * @Title: AlipayController.java
 * @Package com.sihai.controller
 * @Description: 前往支付宝第三方网关进行支付
 * Copyright: Copyright (c) 2017
 * Company:FURUIBOKE.SCIENCE.AND.TECHNOLOGY
 *
 * @author sihai
 * @date 2017年8月23日 下午8:50:43
 * @version V1.0
 */
 @RequestMapping(value = "/goAlipay", produces = "text/html; charset=UTF-8")
 @ResponseBody
 public String goAlipay(String orderId, HttpServletRequest request, HttpServletRequest response) throws Exception {

 Orders order = orderService.getOrderById(orderId);

 Product product = productService.getProductById(order.getProductId());

 //获得初始化的AlipayClient
 AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);

 //设置请求参数
 AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
 alipayRequest.setReturnUrl(AlipayConfig.return_url);
 alipayRequest.setNotifyUrl(AlipayConfig.notify_url);

 //商户订单号,商户网站订单系统中唯一订单号,必填
 String out_trade_no = orderId;
 //付款金额,必填
 String total_amount = order.getOrderAmount();
 //订单名称,必填
 String subject = product.getName();
 //商品描述,可空
 String body = "用户订购商品个数:" + order.getBuyCounts();

 // 该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。该参数数值不接受小数点, 如 1.5h,可转换为 90m。
 String timeout_express = "1c";

 alipayRequest.setBizContent("{"out_trade_no":""+ out_trade_no +"","
 + ""total_amount":""+ total_amount +"","
 + ""subject":""+ subject +"","
 + ""body":""+ body +"","
 + ""timeout_express":""+ timeout_express +"","
 + ""product_code":"FAST_INSTANT_TRADE_PAY"}");

 //请求
 String result = alipayClient.pageExecute(alipayRequest).getBody();

 return result;
 }

这段代码都可以在阿里支付的demo里面找到的,只需要复制过来,然后改改,整合到ssm环境即可。

上面就是将阿里支付宝支付整合到ssm的全过程了。