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));
}
}
-
支付宝沙盒环境配置
根据的是支付沙盒环境支付,不能做为正式上线支付,正式上线支付需要续签(需要商户认证)
支付的时候是用自己配置沙盒环境的商户账号进行模拟支付。
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";
}
-
支付宝支付控制器
该支付是采用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);
}
}
- 演示移动端页面和微信公众号授权效果
采用的是微信开发工具访问域名的前端项目效果图
- 演示网页端支付宝沙盒环境效果
点击下单,唤器支付宝,使用沙盒账号支付
- 项目地址
注:该项目是打算用在微信页面的H5页面,用了支付宝支付,但还没实现在微信页面唤起支付宝App,
本来是有微信支付的....,但是过期了就不能用了。该项目也有微信支付的实现...
后端的话直接去github找好了
该项目域名访问地址为 www.gouptea.top (偶尔后端Springboot jar包挂掉可能会导致Nginx报错)
对于域名备案、微信公众号配置、支付沙盒环境详细步骤也有,可点击个人主页找找。
github下载地址:https://github.com/mi499938150/springboot-appointment