Springboot整合mybatis、微信授权、支付宝沙盒支付实现基于前后端分离个人美发预约管理系统

1.前言

在这里主要介绍使用Springboot整合mybatis,并实现微信授权、支付宝沙盒环境支付的前端分离美发预约管理系统。

后端使用技术:

Springboot、mybatis、pagehelper、freemarker、mapper插件、微信授权、alipay SDK、boostrap、Vue。

开发工具:idea

数据库: mysql

前端使用技术:

采用Vue的 px2rem、Vux ui 组件实现移动端页面

项目属于前后端分离,后端除了模块的增删查改、还提供前端的服务接口。

前端Vue使用axios调用后端接口并将其传染数据。

项目地址为:

2.表的结构

[图片上传中...(image-87cb3a-1581261988332-0)]

项目相对较小,只有5张来展现。

分别是预约信息表、预约分类表、预约订单表、详情表、微信用户表。

在这个项目使用的mapper插件来实现增删查改。

3.maven配置

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-parent</artifactId>

<version>2.2.1.RELEASE</version>

<relativePath/>

 </parent>

<groupId>com.mi</groupId>

<artifactId>springboot-order-haircut</artifactId>

<version>0.0.1-SNAPSHOT</version>

<name>haircut</name>

<description>Demo project for Spring Boot</description>

<properties>

<java.version>1.8</java.version>

</properties>

<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-devtools</artifactId>

<scope>runtime</scope>

<optional>true</optional>

</dependency>



     <dependency>

<groupId>tk.mybatis</groupId>

<artifactId>mapper-spring-boot-starter</artifactId>

<version>2.0.2</version>

</dependency>

     <dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-jdbc</artifactId>

</dependency>

     <dependency>

<groupId>com.github.pagehelper</groupId>

<artifactId>pagehelper-spring-boot-starter</artifactId>

<version>1.2.5</version>

</dependency>

<dependency>

<groupId>com.google.code.gson</groupId>

<artifactId>gson</artifactId>

</dependency>

<dependency>

<groupId>org.projectlombok</groupId>

<artifactId>lombok</artifactId>

<optional>true</optional>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

<exclusions>

<exclusion>

<groupId>org.junit.vintage</groupId>

<artifactId>junit-vintage-engine</artifactId>

</exclusion>

</exclusions>

</dependency>

公众号(包括订阅号和服务号)

-->

     <dependency>

<groupId>com.github.binarywang</groupId>

<artifactId>weixin-java-mp</artifactId>

<version>3.4.0</version>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-configuration-processor</artifactId>

<optional>true</optional>

</dependency>

     <dependency>

<groupId>cn.springboot</groupId>

<artifactId>best-pay-sdk</artifactId>

<version>1.3.0</version>

</dependency>

     <dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-freemarker</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-redis</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-websocket</artifactId>

</dependency>

<dependency>

<groupId>javax.servlet</groupId>

<artifactId>javax.servlet-api</artifactId>

</dependency>

    <dependency>

<groupId>com.alipay.sdk</groupId>

<artifactId>alipay-sdk-java</artifactId>

<version>4.9.13.ALL</version>

</dependency>

     <dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-redis</artifactId>

</dependency>

</dependencies>

<build>

<finalName>haircut</finalName>

<plugins>

<plugin>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-maven-plugin</artifactId>

</plugin>

</plugins>

</build>
</project>

4.yml 配置文件

#沙箱账号
pay:
  alipay:
    gatewayUrl: https://openapi.alipaydev.com/gateway.do
    appid: 2016101800718136
    appPrivateKey: MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCOUnp5ts0UCcjEbGfjZW9CiIMOKj9iW7/hk5nm7fky+C+wQ/74VsxuCY88sSq0hwLmjysWfDSoCgGKwY/cXboeh7AeFSDxdIMIhQlj2HTYEOxh3BYJaKpM71kndK4SPSQS/QJ5jzXE5Ey+aQ7YfPX2Ohp3XGlN/WVQKCiKGO0wWp1Hv33FBAfmmhAofMqy1NwV0UjiFrfvVBp4/WFzOnQ7bsGYG9kIFY4EuV0an1b12NIdsekuRyAZ216iAT7oV5pLiAXTkkOPqHADqkIhE1kg8C+ECPUud3dmMyM/LxeqWQ0q9WI76rj/aRphBlc4cAfU+abBCQSOQRf90KZPKILlAgMBAAECggEBAIH43JSO1lY4YTrQbUeDeMnf9R9Yga4HcAJHU0NLjEp50MM+NXkBe4v5+u9INGHM8l8v2/+aylOzX5kiD4kFp1T+QV4XmZAoAQokxGCEaqBvRBBSd2V8ShoccuTPb7CEWY9ls37jxAzdGSDCvKYD6HNGuKjMofZxNLaxFeSXwvRmS76a0XYfhqbauF7tCS9uURINGEihMDNLrIEQl1mAKqW+rgxegKn4njIMEA0AXFhZL/TnNtN+obC6EG/N21eD4NFdef5s5I95kb9Y0Qj/HeUxzHbi0bLyejFcbC73oMuQvTCi80qe+s65UOf9wBKeREC18rVa+u0Yk98UrJNLS7kCgYEA3YWiW8guBdFEIGaap2HmorxotFmXrUWodS40m/JhmEqKEwD5BR3KYYHY+nG+uK2H13CNi4nyAXxYwahv8u4mViPD0iiPzWHFtwOCrVFYcoxyTrG0IzGmrVg2UaIR3aE/cDDO3AyNsQKAznbsY1omze7FhSfGiZK4Cadpb2M8QZMCgYEApHkw4qT7uyvwoFY7uPY8TQGlGnnCPET/w90QtwUP99AJmLPyLDTZ4gxQxuHZn5I7KdIt0eXFFlZI31WbRnZTJDlLNORJyWOxu6yfuN7R6LnXyi7RyP0uxDz1exXZBVvpZ3PztZ09M5e0XMddzMEqEO9fmarKJgRJ+li6TKjE1KcCgYEAh36zvlwE+n3zo7Xepr8VKTkA+j9KrStMTNCEUVbCJzqAlfskVeLQ5S9dHmLwe1l5G2e2zEEGC66ZQ2rZfsf4HvwlTKiOvNsu6jB1f7mf1gDd8hBz1IsMHj80il4Ne3ijquXPwXzUNg8H5kGLeYGs9o0zt6yKnZ9mflEuBnm2Y40CgYEAi7p94n6hcfExezXnhQqETjOwjV6VulgwJbjgY2xElZbDIFz3x8CavmUSFvR2yw8TfkMWNDUNDB3/yOTUhrctiR+3mda8LQCqVTOhehCqqhmAjz7ZcPRPT94t+wSjm97q2r3ydP+BqBwg2ZVyRepxD3QddtJW7JdGNg49L7VNiw8CgYBksokV/QY7jLDzTD4vz/Ajj3N3cipYT//d9qCzmMZVM66cfuQxKpqN7O1s2qdBUeVl6RpSrXxFU0FeEhyNMT6mS4ia7HnY1WheDMElCIjPLQoAX32ue0QFFhv/xt7n82IO+4k2lDANCSPec/gcohqIilfuXPllrMGIq3gEM3pq9w==
    alipayPublicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsNXDiY6rz6YlyI877zLjp+T7RnXpL1zKqGnhIqQxImRv141mELGH71tpuel2tXMHso6aAEYDog8lcw2OJ9CA3gotKaXERQvAIt1FgeQE7BDHKttfdbMP8YshbA9Mqo/wvEEp03GkJun+Vg33W10eXOyKBU+Dw68EPerRf1a9932qM8sSpuAmkB+KU7HKrVBN2Hyk6raVbmoqKjula2wIM/xT/YbYtkdztNJH6vfeflP/IHZpoM/46bYHzMx+I1dq/dnBpFc15f/lGIUxfFpBUlpg0KfPrMDREZIFaSreJmVoCM5wfeQ1q8M+euJPYyboisT1zhAZDBos6uxejmd+aQIDAQAB
    returnUrl: http://www.gouptea.top/haircut/alipay/return
    notifyUrl: http://www.gouptea.top/haircut/alipay/notify

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: 123456
    url: jdbc:mysql://localhost/haircut?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC

  jackson:
    default-property-inclusion: non_null
  thymeleaf:
    prefix: classpath:/templates/
    suffix: .html
    mode: HTML5
    encoding: UTF-8
    enabled: true
    servlet:
      content-type: text/html
    cache: false
  freemarker:
    template-loader-path: classpath:/templates/
    charset: UTF-8
    cache: false
    expose-request-attributes: true
    expose-session-attributes: true
    expose-spring-macro-helpers: true
    suffix: .ftl
  mvc:
    static-path-pattern: /**

mybatis:
  mapper-locations: classpath:mapper/*Mapper.xml
  type-aliases-package: com.mi.haircut.domain

pagehelper:
  helper-dialect: mysql
  reasonable: true
  support-methods-arguments: true
  params: count==countSql
  page-size-zero: true

server:
  servlet:
    context-path: /haircut
  port: 8080

logging:
  file:
    path: E:/logs

wechat:
  mpAppId: wx5904758eb34b27d1
  mpAppSecret: c14567d2bfc1bd1f1091cca02c8fe7c8
  notifyUrl: http://www.gouptea.top/haircut/pay/notify

5.微信MpConfig配置

是使用用来配置微信公众号的环境,授权的是一个测试微信公众号,需要到微信官方申请接口并进行关注。

package com.mi.haircut.config;

import me.chanjar.weixin.mp.api.WxMpConfigStorage;
import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

/**
 * 微信公众号配置
 */
@Component
public class WechatMpConfig {

    @Autowired
    private WechatAccounConfig wechatAccounConfig;

    @Bean
    public WxMpService wxMpService(){
        WxMpService wxMpService = new WxMpServiceImpl();
        wxMpService.setWxMpConfigStorage(wxMpConfigStorage());
        return  wxMpService;
    }

    //配置环境
    @Bean
    public WxMpConfigStorage wxMpConfigStorage(){
        WxMpInMemoryConfigStorage wxMpInMemoryConfigStorage = new WxMpInMemoryConfigStorage();
        wxMpInMemoryConfigStorage.setAppId(wechatAccounConfig.getMpAppId());
        wxMpInMemoryConfigStorage.setSecret(wechatAccounConfig.getMpAppSecret());
        return wxMpInMemoryConfigStorage;
    }
}

6.微信授权控制器

这个控制器是用来通过访问H5前端页面调取微信公众号是否同意授权信息,点击同意后就拉取用户的微信信息。

主要为下方两个方法步骤:
第一步 authorize方法:当用户访问的时候,需要配上一个回调给自己的域名地址(第二个放会用到)

第二步 userInfo 方法:当用户点击同意授权后会随机生成一个code代码,通过code去换取用户的openid,并拉取用户信息,然后通过自己回调的地址带个openid参数,回到自己的页面上。此时可以通过判断的方式来进行授权的用户存储到自己本地的数据库。

package com.mi.haircut.controller;

import com.mi.haircut.Vo.ResultVo;
import com.mi.haircut.domain.WeChatUser;
import com.mi.haircut.enums.ResultEnum;
import com.mi.haircut.exception.AppointException;
import com.mi.haircut.mapper.WechatUserMapper;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;

/**
 * @author : Rong
 * @date : 2020/1/12
 * @Desc: 微信授权
 */
@Controller
@RequestMapping("/wechat")
@Slf4j
public class WechatController {

    @Autowired
    private WxMpService wxMpService;
    @Autowired
    private WechatUserMapper wechatUserMapper;
    /**
     * 微信授权
     */
    @GetMapping("authorize")
    public String  authorize(@RequestParam("returnUrl")String returnUrl, HttpServletResponse response) throws IOException {
        // 1. 配置
        // 2. 调用方法
        String url = "http://www.gouptea.top/haircut/wechat/userInfo";
        String redirectUrl = wxMpService.oauth2buildAuthorizationUrl(url, WxConsts.OAuth2Scope.SNSAPI_USERINFO, URLEncoder.encode(returnUrl));
        log.info("[微信网页授权]获取code,result={}",redirectUrl.toString());
        return "redirect:" + redirectUrl;
      }


@GetMapping("/userInfo")
public ModelAndView userInfo(@RequestParam("code") String code, @RequestParam("state")String returnUrl, HttpServletResponse response) throws IOException {
    WxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken();
    try{
        wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code);
    } catch (WxErrorException e) {
        log.error("[微信网页授权]{}",e);
        throw new AppointException(ResultEnum.WX_MP_ERROR.getCode(),e.getError().getErrorMsg());
    }
    String openId = wxMpOAuth2AccessToken.getOpenId();
    log.info("[微信openid]openid={}",openId);

    String str = returnUrl + "?openid=" + openId;
    log.info("【微信网页返回地址】:{}",str);
    try {
        WxMpUser wxMpUser = wxMpService.oauth2getUserInfo(wxMpOAuth2AccessToken,null);
        log.info("【微信网页授权获】获取用户信息:{}",wxMpUser);
        //判断是否为空
        if (!StringUtils.isEmpty(wxMpUser)){
//            //查询是否存在
            WeChatUser wChatUser = wechatUserMapper.selectByPrimaryKey(openId);
            //不存在就添加到数据库中
            if (StringUtils.isEmpty(wChatUser)) {
                WeChatUser weChatUser = new WeChatUser();
                weChatUser.setOpenId(wxMpUser.getOpenId());
                weChatUser.setSex(wxMpUser.getSex());
                weChatUser.setSexDesc(wxMpUser.getSexDesc());
                weChatUser.setNickName(wxMpUser.getNickname());
                weChatUser.setHeadImgUrl(wxMpUser.getHeadImgUrl());
                weChatUser.setLanguage(wxMpUser.getLanguage());
                weChatUser.setCountry(wxMpUser.getCountry());
                weChatUser.setProvince(wxMpUser.getProvince());
                weChatUser.setCity(wxMpUser.getCity());
                wechatUserMapper.insert(weChatUser);
            }
        }
    } catch (WxErrorException e) {
        e.printStackTrace();
    }
    return new ModelAndView(new RedirectView(str));
   }
}
  1. 支付宝沙盒环境配置

    根据的是支付沙盒环境支付,不能做为正式上线支付,正式上线支付需要续签(需要商户认证)
    支付的时候是用自己配置沙盒环境的商户账号进行模拟支付。

public class AlipayConfig {

 // 应用ID,支付宝提供的APPID,上面截图中有提到
 public static String app_id = "2016101800718136";

 // 商户私钥,您的PKCS8格式RSA2私钥
// public static String merchant_private_key = "这里写入上面生成的**应用私钥**";

 public static String merchant_private_key = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCDk0bRf9nf5Og6wxLSZ0h+Vj1IFR3MgkxPQqlR0nmDOJ/cnq4WRTHHIaog5nCP0HPqD+O47rtIGYFsnmDGWrG9rHvczW/GErP+pn6fS31nR2GrTDY1fIXwt5CUXaUb7j6OPrJsw6pf6GGt8fsCHgjBSh+CNcEmJDkiJqMAI50N2sTdji/fxlrcfstTgOSryvKY7LE2kMs3/eSYqnJQerGj42VavkDV0x77Awlv5dpHjFxFoo1jtdlGgaTYKQCbfN6G9Vba3B8bHFlq4ETKVrq0fg70NzMWk/UhFFNuvxG5TpsF6MIp1loaOJbPq70FMMKoiJLZdT9JqlBmRziOKeFBAgMBAAECggEAXw9nyfKaAdXLJrFLhvISARzjd5GyDtBQu68Iz9HF8tVVQjruwa5KUXl0BgMXbgAHzyKdvz3T1zp+NHCUsJpT8hqM/rD6QVu/6Yp2zzXmK1j6Kp2MSMZnqsukzFx/7pcJYRHRLR2MmXA2Kks6s4PphWS9MQEPRDRFhvPtLiuMy7Wq4KFRit0iQViNpL/lk/vIVI7ENTNCJXy5Nx9HOLzLB0dssmeHr0gL3dRKa1ZLGwUBBiv5YXfbzuWS5i17YCMfBUh1OLk9v0bi8Nu7zCBWb1QI9gg5jB7kpaQ1Q6ZI0+G+xn0lH4+MMIGWNP8oEuUGKp8EYXDZfGa6KX9OnXmhlQKBgQC8JyV/gyY7h7iwc3lanmrWYqRiVWMY9dGgwOo/61xM1xRSTZ1fMppmvkCMdEoyzWtwrzgkn+92G9TB2drGYONd6jVlNG/Y2ociR1D8DB5ACJgvnEdv20qsOdACitVIchkRdSXqaD3cp2YVa2vsg2ZPpcqBXiPYe63t4CH+GG0CdwKBgQCzBVAMwVkRQUirpcv6S5D5Ui4oSXs1sh+6g7DUSr61OqiytJv++aM/DvsNJefoSPcZeRLfVfmlfHLzNDJ2FSwJzHopsGw6hyAkzml2BOl39uxzZi6fa+EDXu7rFAYt8EAt9Yqs0tK0dKJ9jLobfH3j/uGQIVmSSf9P7eWPFKuwBwKBgQC1GJywAaR/8d8i/tIUFZxRYrpD51mtgZTWPDh7c2bwkqd9nDTXlxYjxATO63MrOKqr2AqavdG3BYyfVLeM716IW1Ava+wndhZROQFKx8Mp8NvCH5JmqFRUNoTunYAx7ZgRRIdM+i5ovjq0bSOAjuyfxryGDf1Eda5v4aX2Mr5hewKBgDZP91BXXJlSkCSbYX4nbO1nVF+eo4XP67Zfe8d8gc1j5YiKKQW7YR6hgeMkS+56LJWK2QHvCJV/YzSL8n9Gvxyd77Y0MzGyizr/cJmAtgBSZrxAFQcC6LpoE944LgPD7wTCiPcT4x8if6XNiy0JoPwJ+Q8MPyuVzaLHTy0QnWIDAoGACJAQQ7Q6HBr2QXmFEnsdGqoIxoJyPRQShnRlGzve7fjLQAFrxmWZ5kwgB3zbwchivMyI4xIcNgAmkMebA6MrV+DPVsxSqOKg+D39vHURoPLZnLtfmULXAXb1bvKhd/cgFG2sYEHGporb4nqi+D3rUlMulEpRsTjQsTntVZ+SYA4=";

 // 支付宝公钥,查看地址:https://openhome.alipay.com/platform/appDaily.htm 对应APPID下的支付宝公钥。

// public static String alipay_public_key = "注意是上面再三提示的支付宝公钥";

 public static String alipay_public_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsNXDiY6rz6YlyI877zLjp+T7RnXpL1zKqGnhIqQxImRv141mELGH71tpuel2tXMHso6aAEYDog8lcw2OJ9CA3gotKaXERQvAIt1FgeQE7BDHKttfdbMP8YshbA9Mqo/wvEEp03GkJun+Vg33W10eXOyKBU+Dw68EPerRf1a9932qM8sSpuAmkB+KU7HKrVBN2Hyk6raVbmoqKjula2wIM/xT/YbYtkdztNJH6vfeflP/IHZpoM/46bYHzMx+I1dq/dnBpFc15f/lGIUxfFpBUlpg0KfPrMDREZIFaSreJmVoCM5wfeQ1q8M+euJPYyboisT1zhAZDBos6uxejmd+aQIDAQAB";

 // 服务器异步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问.如果只是测试使用,那么设置成自己项目启动后可以访问到的一个路径,作为支付宝发送通知的路径(有什么用暂时没发现)
 public static String notify_url = "http://localhost:8080/haircut/alipay/alipay-callback-notify-url";


 // 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问.如果只是测试使用,那么设置成自己项目启动后可以访问到的一个路径.是支付正常完成后,会访问的路径.
 public static String return_url = "http://localhost:8080/haircut/alipay/alipay-callback-return-sult";

 // 签名方式,注意这里,如果步骤设置的是RSA则用RSA,如果按照扇面步骤做的话,选择RSA2
 public static String sign_type = "RSA2";
 // 字符编码格式
 public static String charset = "utf-8";
 // 支付宝网关
 public static String gatewayUrl = "https://openapi.alipaydev.com/gateway.do";
}
  1. 支付宝支付控制器

    该支付是采用H5支付页面,可以通过需求自己定义。
    在下单进行支付的时候,需要通过 alipayRequest.setBizContent生成自己订单号和金额。
    支付的时候会有两个方法,一个异步回调和同步回调。
    在这里感觉就只用到同步回调...

@RestController
@RequestMapping("alipay")
@Slf4j
public class WapPayController {

    @Autowired
    private  AppointOrderService orderService;

    @Autowired
    private WapPayService wapPayService;

    //支付成功返回主页面
    public static String redirectUrl = "www.gouptea.com";

    @RequestMapping("index")
    public ModelAndView aliPay(){
        return new ModelAndView("alipay/index");
    }

    @RequestMapping("wapPayServlet")
    public String doWapPay(@Valid OrderForm orderForm,
                                               BindingResult bindingResult,
                           @RequestParam(value = "subject")String subject,
                           @RequestParam(value = "total_amount")String total_amount){

        log.info("【开始创建订单....】");
        log.info("【获取参数】result = {}",orderForm);
        log.info("[---------]");
        if (bindingResult.hasErrors()){
            log.error("[创建订单]参数不正确,orderForm={}",orderForm);
            throw new AppointException(ResultEnum.PARAM_ERROR.getCode(),
                    bindingResult.getFieldError().getDefaultMessage());
        }
        OrderDTO orderDTO =  OrderFormOrderDtoConverter.convert(orderForm);
        OrderDTO createResult = orderService.create(orderDTO);

        //获得初始化的AlipayClient,将上面创建的配置类中的变量设置到该对象中
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key,
                "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);
        //设置请求参数,并把配置类中的两个路径设置进去  PC端
//        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
//        alipayRequest.setReturnUrl(AlipayConfig.return_url);
//        alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
        AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();//创建API对应的request
        alipayRequest.setReturnUrl(AlipayConfig.return_url);
        alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
        //如果想正常调用接口则需要传一些必要参数,out_trade_no:订单号,保证唯一性,支付宝根据该参数生成你的支付单号,total_amount:需要支付的金额,注意是String型,且金额计数的分割","不能存在(例如1,000就是错误的参数),subject:对物品进行描述,product_code:是支付类型.更多详细的参数信息参考链接: [https://docs.open.alipay.com/api_1/alipay.trade.page.pay](https://docs.open.alipay.com/api_1/alipay.trade.page.pay)
        String orderId = keyUtil.genUniqueKey();
        try {
            alipayRequest.setBizContent("{\"out_trade_no\":\""+ createResult.getOrderId() +"\","
                    + "\"total_amount\":\""+total_amount +"\","
                    + "\"subject\":\""+ subject +"\","
                    + "\"product_code\":\"QUICK_WAP_PAY\"}");
            // FAST_INSTANT_TRADE_PAY PC
            // QUICK_WAP_PAY mobile
            //请求
            String result;
            //发送请求并返回
            result = alipayClient.pageExecute(alipayRequest).getBody();
            System.out.println("*********************\n返回结果为:"+result);
            return result;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
    }

    @RequestMapping("alipay-callback-return-sult")
    public String successResult(HttpServletRequest request, HttpServletResponse response){
        //可以根据request.getParameterMap()获得到调用接口时传递的一些参数去做后续的业务处理
        Map<String, String[]> parameterMap = request.getParameterMap();
        String[] out_trade_nos = parameterMap.get("out_trade_no");
        String id = out_trade_nos[0];
        log.info("【return】 id = {},time = {}",id,new Date());
        //跳转到其他页面或重定向到其他方法
        //修改订单支付状态
        wapPayService.updateInfo(id);

        return "redirect:" + redirectUrl;

    }
    @RequestMapping("alipay-callback-notify-url")
    public ResultVo failResult(HttpServletRequest request, HttpServletResponse response){
        Map<String, String[]> parameterMap = request.getParameterMap();
        String[] out_trade_nos = parameterMap.get("out_trade_no");
        String uuid = out_trade_nos[0];
        log.info("【notify】 uuid = {},time = {}",uuid,new Date());

        return ResultVoUtil.success(uuid);
    }
}
  1. 演示移动端页面和微信公众号授权效果
    采用的是微信开发工具访问域名的前端项目效果图
image.png
  1. 演示网页端支付宝沙盒环境效果
    点击下单,唤器支付宝,使用沙盒账号支付
image.png
  1. 项目地址
    注:该项目是打算用在微信页面的H5页面,用了支付宝支付,但还没实现在微信页面唤起支付宝App,
    本来是有微信支付的....,但是过期了就不能用了。该项目也有微信支付的实现...
    后端的话直接去github找好了
    该项目域名访问地址为 www.gouptea.top (偶尔后端Springboot jar包挂掉可能会导致Nginx报错)
    对于域名备案、微信公众号配置、支付沙盒环境详细步骤也有,可点击个人主页找找。
    github下载地址:https://github.com/mi499938150/springboot-appointment
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容