目录

  • 前言
  • 1. 支付安全
    • 1.1 对称加密和非对称加密
    • 1.2 身份认证
    • 1.3 摘要算法
    • 1.4 数字签名和数字证书
  • 2. 项目初期
    • 2.1 构建测试
    • 2.2 引入Swagger
    • 2.3 引入lombok
  • 3. 数据库
    • 3.1 实体类
    • 3.2 映射类
    • 3.3 service类
    • 3.4 配置类
    • 3.5 业务逻辑
  • 4. 前端界面
    • 4.1 vue
  • 5. 基础支付API V3
    • 5.1 配置yml和配置类
    • 5.2 加载私钥文件
    • 5.3 获取签名验证器和HttpClient
    • 5.5 API字典和相关工具
  • 6. Native订单
    • 6.1 Native下单

前言

本项目主要通过以下链接进行学习
【尚硅谷】微信支付开发,基于SpringBoot+Vue架构的Java在线支付视频教程

这篇文章结合了自已的思考以及笔记

该项目主要是基于
后端技术有:springboot+springmvc+restful+vue+mybatis-plus+mysql
前端技术有:html+css+vue

本文的框架主要介绍

  • 微信支付的一些引言,关于支付的证书、密钥以及签名
  • 项目的构建到实现
  • 基础支付API接口

本文的框架涉及的知识点 可看我之前的文章
基础知识:

  1. java零基础从入门到精通(全)
  2. javaSE从入门到精通的二十万字总结(一)
  3. javaSE从入门到精通的二十万字总结(二)
  4. javaSE从入门到精通的二十万字总结(三)

服务端:

  1. Spring框架从入门到学精(全)
  2. SpringMVC从入门到精通(全)
  3. Mybatis从入门到精通(全)
  4. MyBatis-plus从入门到精通(全)

数据库

  1. 数据库中增删改常用语法语句(全)
  2. 数据库查询常用语句语法

web服务器:Tomcat详细配置(全)

项目管理

  1. Maven实战从入门到精通(全)
  2. Maven详细配置(全)

前端知识点:

  1. html从入门到精通(全)
  2. css属性从入门到精通(全)
  3. JavaScript从入门到精通(全)

1. 支付安全

  • 明文:加密前的消息叫“明文”(plain text)
  • 密文:加密后的文本叫“密文”(cipher text)
  • 密钥:只有掌握特殊“钥匙”的人,才能对加密的文本进行解密,这里的“钥匙”就叫做“密钥”(key)

按照密钥的使用方式,加密可以分为两大类:对称加密和非对称加密

1.1 对称加密和非对称加密

对称加密
特点:只使用一个密钥,密钥必须保密,常用的有 AES算法

  • 优点:运算速度快
  • 缺点:秘钥需要信息交换的双方共享,一旦被窃取,消息会被破解,无法做到安全的密钥交换

非对称加密
特点:使用两个密钥:公钥和私钥,公钥可以任意分发而私钥保密,常用的有 RSA

  • 优点:黑客获取公钥无法破解密文,解决了密钥交换的问题
  • 缺点:运算速度非常慢

1.2 身份认证

  • 公钥加密,私钥解密的作用是加密信息
  • 私钥加密,公钥解密的作用是身份认证

一般来说公钥加密之后,公钥都是公开的,通过私钥进行解密

而如果反过来,通过私钥加密,公钥解密,那就是身份认证,专属自已的唯一钥匙

1.3 摘要算法

主要为了保证数据没有被修改过,保证信息的完整性

摘要算法就是我们常说的散列函数、哈希函数(Hash Function),它能够把任意长度的数据“压缩”成
固定长度、而且独一无二的“摘要”字符串,就好像是给这段数据生成了一个数字“指纹”。

主要的特性有:

  • 不可逆:只有算法,没有秘钥,只能加密,不能解密
  • 难题友好性:想要破解,只能暴力枚举
  • 发散性:只要对原文进行一点点改动,摘要就会发生剧烈变化
  • 抗碰撞性:原文不同,计算后的摘要也要不同

为了凸显数据的完整性,通过加入摘要算法,将其添加进数据中
而拿到数据的人为了验证数据完整性,通常也要通过摘要算法,也就是哈希,判断数据前后是否一致,依次判定是否有修改

但如果中间被截获,生成新的摘要算法,很难判断是否又被其他人修改

1.4 数字签名和数字证书

数字签名:
将数据通过摘要算法之后还要再用私钥加密变成数字签名
而获得数据的人,需要通过公钥进行解密以及通过摘要算法来验证数据的完整性

上面的公钥可以伪造
为此多了一个数字证书

数字证书:
数字证书解决“公钥的信任”问题,可以防止黑客伪造公钥。
不能直接分发公钥,公钥的分发必须使用数字证书,数字证书由CA颁发

具体数字证书生成流程如下:
通过哈希算法也就是摘要算法生成信息再通过CA的私钥加密变成数字证书

A用数字证书发送数据,B取到数据后,通过哈希算法也就是摘要算法进行确定完整性,再通过CA的公钥判定是否可以取出,取出之后就是A的公钥了。B再用取到的A公钥进行解密,以及摘要算法确定数据的完整性

在科普一下https的数字证书:

2. 项目初期

2.1 构建测试

创建springboot的项目
通过idea编译器 new 一个spring initializr的项目,java8的版本
以及服务器使用https://start.aliyun.com,会比较快

具体关于springboot的相关知识可看我之前的文章
springboot从入门到精通(全)

此处修改以下pom文件下的依赖文件改成web,主要为了网页的启动

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

配置一个端口号(资源文件下)

server:port: 8090 #服务端口spring:application:name: payment-demo #应用的名字

配置一个界面,进行测试springboot的启动

@RestController //主要是为了传输json数据的一个注解
@RequestMapping("/api/product")
public class ProductController {@GetMapping("/test")public String test(){return "hello";}
}

在浏览器中输入url为
http://localhost:8090/api/product/test 进行测试

几个注意事项:
在搭建springboot的时候
使用maven管理jar包的时候不要混乱使用版本号
(注解不要混乱使用jar包各个版本)

2.2 引入Swagger

自动生成接口文档和相关的测试界面
测试get post delete等界面的时候比较方便

一个是依赖文件一个是ui的展示界面依赖包

<!--Swagger-->
<dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.7.0</version>
</dependency>
<!--Swagger ui-->
<dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.7.0</version>
</dependency>

配置一个配置类

通过bean对象注入
如一个文本的文档对象

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;@Configuration
@EnableSwagger2
public class Swagger2Config {@Beanpublic Docket docket(){return new Docket(DocumentationType.SWAGGER_2).apiInfo(new ApiInfoBuilder().title("码农研究僧微信支付案例接口文档").build());}
}

之后在网址中输入如下页面http://localhost:8090/swagger-ui.html#/

为了更好的通过url与swagger的更好融合
可以在业务层的代码模块中增加如下,@Api(tags = "商品管理")@ApiOperation("测试接口")
这个注解@ApiOperation(" )只有一个value值 ,所以value值可以省略

@Api(tags = "商品管理")
@RestController //主要是为了传输json数据的一个注解
@RequestMapping("/api/product")
public class ProductController {@ApiOperation("测试接口")@GetMapping("/test")public String test(){return "hello";}
}

之后在页面中就会这么显示

2.3 引入lombok

为了前后端更好的交互,定义一个统一的结果
主要显示响应码,响应消息
再依赖包中要放一个lombok
主要是可以简化开发,自动生成get、set等方法

(前提是有lombok的插件)

<!--lombok-->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency>

主要的代码模块为

@Data
public class R {private Integer code; //响应码private String message; //响应消息private Map<String, Object> data = new HashMap<>();public static R ok(){R r = new R();r.setCode(0);r.setMessage("成功");return r;}public static R error(){R r = new R();r.setCode(-1);r.setMessage("失败");return r;}public R data(String key, Object value){this.data.put(key, value);return this;}}

通过@Data这个注解查看其structure结构,也可以看到自动生成了get和set等方法

关于@Data这个注解可看我之前的文章
spring中@Data注解详细解析

给前端传输一些具体的信息
通过data这个哈希进行传输

public R data(String key, Object value){this.data.put(key, value);return this;}

在显示界面中通过输入一定的值就可看到
链式操作,可以多个值传输

@ApiOperation("测试接口")@GetMapping("/test")public R test(){return R.ok().data("message", "hello").data("now", new Date());}

特别补充一下如果这样传输new Date()的数据,不是一个标准的格式
如果要换成想要的格式
可以在资源文件中进行添加(本身时json的数据格式)
yyyy-MM-dd HH:mm:ss 年月日,分时秒,GMT+8以及时区

jackson:date-format: yyyy-MM-dd HH:mm:sstime-zone: GMT+8

3. 数据库

通过navicat软件或者本机的mysql进行构建数据库
通过运行特定的数据库脚本或者自已书写数据库

具体sql的脚本如下

USE `payment_demo`;/*Table structure for table `t_order_info` */CREATE TABLE `t_order_info` (`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '订单id',`title` varchar(256) DEFAULT NULL COMMENT '订单标题',`order_no` varchar(50) DEFAULT NULL COMMENT '商户订单编号',`user_id` bigint(20) DEFAULT NULL COMMENT '用户id',`product_id` bigint(20) DEFAULT NULL COMMENT '支付产品id',`total_fee` int(11) DEFAULT NULL COMMENT '订单金额(分)',`code_url` varchar(50) DEFAULT NULL COMMENT '订单二维码连接',`order_status` varchar(10) DEFAULT NULL COMMENT '订单状态',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;/*Table structure for table `t_payment_info` */CREATE TABLE `t_payment_info` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '支付记录id',`order_no` varchar(50) DEFAULT NULL COMMENT '商户订单编号',`transaction_id` varchar(50) DEFAULT NULL COMMENT '支付系统交易编号',`payment_type` varchar(20) DEFAULT NULL COMMENT '支付类型',`trade_type` varchar(20) DEFAULT NULL COMMENT '交易类型',`trade_state` varchar(50) DEFAULT NULL COMMENT '交易状态',`payer_total` int(11) DEFAULT NULL COMMENT '支付金额(分)',`content` text COMMENT '通知参数',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;/*Table structure for table `t_product` */CREATE TABLE `t_product` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '商品id',`title` varchar(20) DEFAULT NULL COMMENT '商品名称',`price` int(11) DEFAULT NULL COMMENT '价格(分)',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;/*Data for the table `t_product` */insert  into `t_product`(`title`,`price`) values ('Java课程',1);
insert  into `t_product`(`title`,`price`) values ('大数据课程',1);
insert  into `t_product`(`title`,`price`) values ('前端课程',1);
insert  into `t_product`(`title`,`price`) values ('UI课程',1);/*Table structure for table `t_refund_info` */CREATE TABLE `t_refund_info` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '退款单id',`order_no` varchar(50) DEFAULT NULL COMMENT '商户订单编号',`refund_no` varchar(50) DEFAULT NULL COMMENT '商户退款单编号',`refund_id` varchar(50) DEFAULT NULL COMMENT '支付系统退款单号',`total_fee` int(11) DEFAULT NULL COMMENT '原订单金额(分)',`refund` int(11) DEFAULT NULL COMMENT '退款金额(分)',`reason` varchar(50) DEFAULT NULL COMMENT '退款原因',`refund_status` varchar(10) DEFAULT NULL COMMENT '退款状态',`content_return` text COMMENT '申请退款返回参数',`content_notify` text COMMENT '退款结果通知参数',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

在java代码模块中
引入数据库的依赖包

<!--mysql 驱动-->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency><!--MyBatis-Plus:是MyBatis的增强-->
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.1</version>
</dependency>

添加数据库的连接

  datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/payment_demo?serverTimezone=GMT%2B8&characterEncoding=utf-8username: rootpassword: 123456

数据库的版本号如果是5左右,版本名字叫做com.mysql.jdbc.Driver
如果是8的版本号,版本名字叫做com.mysql.cj.jdbc.Driver,即使在pom文件中不给版本号,系统也会默认给8的版本
具体下载方式可以通过maven工程
也可以通过如下进行下载

  1. mysql-connector-java-8.0.26.rar
  2. MySql Connector Java 5.1.23.rar

代码模块中关于数据库
需要数据库表的实体类,映射文件,以及业务逻辑的代码模块
可以通过mybatis的逆向工程一键生成
具体可看我之前的文章
mybatis逆向工程详细配置讲解(全)

3.1 实体类

一共有四张表格,而也有公共的列名称,所以可以设置一个公有类,之后通过继承

在命名的时候如果表格与实体类不一样,可以通过@TableName("t_order_info")这个注解进行映射
如果列名和数据库的列名不一样,也可以映射,但最好使用驼峰的命名规则,mybatisplus就会帮忙转换

(通过lombok的插件 可以自动生成get、set等方法)

如果数据库有主键还需要再主键中配备一个注解
定义主键策略:跟随数据库的主键自增@TableId(value = "id", type = IdType.AUTO)

3.2 映射类

继承BaseMapper

这个类,是mybatis-plus中的统用maper

动态的生成一些特定的接口

xml文件也没有一些书写代码

补充:
再编译之后 target目录中,没有生成xml文件
默认情况下,java目录下非java代码生成不了

资源路径搭配的选项
让maven 中把非java文件也生成

<build><!-- 项目打包时会将java目录中的*.xml文件也进行打包 --><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources></build>

让运行文件能够找到xml文件

应用程序的mapper如何找到
主要是这一行代码

mapper-locations: classpath:com/paymentdemo/mapper/xml/*.xml

顺便补充一下日志的配置文件

3.3 service类

继承了IService

定义了一些增删改查等抽象方法还有一些分页以及批量处理的方法

3.4 配置类

主要是开启事务
以及扫描映射文件

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;@Configuration
@MapperScan("com.paymentdemo.mapper")
@EnableTransactionManagement //启用事务管理
public class MyBatisPlusConfig {}

3.5 业务逻辑

添加完数据库之后
就可以通过调用数据库的数据

@CrossOrigin //开放前端的跨域访问
@Api(tags = "商品管理")
@RestController
@RequestMapping("/api/product")
public class ProductController {@Resourceprivate ProductService productService;@GetMapping("/list")public R list(){List<Product> list = productService.list();return R.ok().data("productList", list);}}

之后在页面中就可以访问到数据

http://localhost:8090/swagger-ui.html#!/21830216973164929702/listUsingGET

同时在终端中也可以看到日志的输出

4. 前端界面

前端界面主要是vue+javascript+html

刚开始是安装node的安装包,可以通过官网进行安装

安装完之后,再cmd命令下搜node -v即可查到版本号

在前端搭建的项目中输入 npm run serve

默认是开启了前端的界面
但是搭建了后端界面,以及前端界面之后,是没有进行连接的,所以登陆进去会出错

前端的端口号中有为8080,但是后端的端口号为8090,所以是不一样的端口号,需要进行跨域

通信的方式为ajax方式
在后端的代码中需要添加一个注解,代表是进行跨域的请求访问
@CrossOrigin //开放前端的跨域访问

4.1 vue

具体打开vue的代码模块通过vscode这个软件
具体怎么安装可通过官网进行下载
一般新手添加三个插件比较好(chinese的中文包、vuehelper的帮助文档等)

一般如果不安装镜像进行下载的话,会通过国内的链接进行下载,一般会比较卡
所以再cmd命令行下面输入这两行命令

  • npm config set registry https://registry.npm.taobao.org ,npm install的安装都会经过淘宝的镜像地址进行下载

  • npm install -g @vue/cli 进行全局的安装脚手架

正常安装情况下:(出现warn不要怕,出现error要害怕)

如果不能安装可查看我这篇文章
出现npm ERR code EPERM npm ERR syscall mkdir npm ERR path B:\nodejs\node_global_cacache 的解决方法

vscode的快捷键:

crtl + ~ 打开终端
ctrl + l 滚动终端到上面

新建一个项目 vue create 项目名
运行这个项目 npm run serve -- --port 端口号
第一个-- 代表是占位符,可以不用填写,第二个–是端口号

vue的页面组件:

  • 页面显示的文件
  • 需要的脚本
  • 页面的样式

具体简单的vue页面架构如下:

App.vue的页面内容主要有:

<!--定义页面结构-->
<template><div></div>
</template><!--定义页面脚本-->
<script>
export default {}
</script>

设计的知识点有:
数据绑定,双向绑定等
简单界面

<!--定义页面结构-->
<template><div><h1>Vue案例</h1><!-- 插值 --><p>{{course}}</p><p><!-- 指令 --><input type="text" v-model="course"></p><p><!-- 事件 --><button @click="toPay()">去支付</button></p></div>
</template><!--定义页面脚本-->
<script>
export default {// 定义数据data () {return {course: '微信支付'}},// 定义方法methods: {toPay(){console.log('去支付')}}
}
</script>

5. 基础支付API V3

引入支付参数:商户号、app的密钥等
加载商户的密钥:非对称密钥的使用,公钥私钥的使用
获取平台证书和验签器:微信平台和网站的两个证书辨别
获取HttpClient对象:远程请求访问,建立远程连接

微信支付API v3的Apache HttpClient扩展,实现了请求签名的生成和应答签名的验证。

如果你是使用Apache HttpClient的商户开发者,可以使用它构造HttpClient。得到的HttpClient在执行请求时将自动携带身份认证信息,并检查应答的微信支付签名。

其java语言的api文档可查看
java api文档

具体如何加载的流程图可看这里
APIv3证书与密钥使用说明

5.1 配置yml和配置类

配置yml

主要是配置微信的支付参数
具体关于微信支付的官网如下
微信支付官网

具体微信支付的参数有:

  • 证书的序列号,就如同CA数字签名
    发送:商户的私钥文件加载到应用程序中主要是为了签名
    签收:之后发送给微信的服务器端,微信根据证书的序列号对应的证书,再通过公钥进行验签

  • APIV3的密钥主要是对称加密

  • APPID就是公众号分配的一个id

  • 微信的服务器地址,向微信服务器端发送支付的请求

  • 接收结果的通知,也要向本地服务器(网站)返回一个结果地址(内网穿透,不一样地址)

# 微信支付相关参数
# 商户号
wxpay.mch-id=手机号
# 商户API证书序列号
wxpay.mch-serial-no=34345964330B66427E0D3D28826C4993C77E631F# 商户私钥文件
wxpay.private-key-path=apiclient_key.pem
# APIv3密钥
wxpay.api-v3-key=UDuLFDcmy5Eb6o0nTNZdu6ek4DDh4K8B
# APPID
wxpay.appid=wx74862e0dfcf69954
# 微信服务器地址
wxpay.domain=https://api.mch.weixin.qq.com
# 接收结果通知地址
# 注意:每次重新启动ngrok,都需要根据实际情况修改这个配置
wxpay.notify-domain=https://500c-219-143-130-12.ngrok.io# APIv2密钥
wxpay.partnerKey: T6m9iK73b0kn9g5v426MKfHQH7X8rKwb

配置类

弄一个配置类主要是为了和微信的支付参数一一对应

@Configuration
@PropertySource("classpath:wxpay.properties") //读取配置文件
@ConfigurationProperties(prefix="wxpay") //读取wxpay节点
@Data //使用set方法将wxpay节点中的值填充到当前类的属性中
@Slf4j
public class WxPayConfig {// 商户号private String mchId;// 商户API证书序列号private String mchSerialNo;// 商户私钥文件private String privateKeyPath;// APIv3密钥private String apiV3Key;// APPIDprivate String appid;// 微信服务器地址private String domain;// 接收结果通知地址private String notifyDomain;// APIv2密钥private String partnerKey;}

配置完的配置文件点击进去之后进不了页面
可以将其配置文件配置为spring的配置文件

方法如下:

添加相对应的依赖包

<!-- 生成自定义配置的元数据信息 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional>
</dependency>

重启启动或者clean之后
可以通过配置文件的信息crtl+右键进入其配置类

5.2 加载私钥文件

需要将其私钥文件引入
主要是为了签名,进行加密

具体api文档可查看
微信支付开发者文档

需要加入依赖包

<dependency><groupId>com.github.wechatpay-apiv3</groupId><artifactId>wechatpay-apache-httpclient</artifactId><version>0.3.0</version>
</dependency>

具体的加载代码如下

代码模块如下

  • 私钥存储在文件
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new FileInputStream("/path/to/apiclient_key.pem"));
  • 私钥为String字符串
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));

在具体的配置类中可以加入这个方法,之后通过测试调用测试是否可以加载

/*** 获取商户的私钥文件* @param filename* @return*/
private PrivateKey getPrivateKey(String filename){try {return PemUtil.loadPrivateKey(new FileInputStream(filename));} catch (FileNotFoundException e) {throw new RuntimeException("私钥文件不存在", e);}
}

具体的测试类调用通过如下

@SpringBootTest
class PaymentDemoApplicationTests {@Resourceprivate WxPayConfig wxPayConfig;/*** 获取商户的私钥*/@Testvoid testGetPrivateKey() {//获取私钥路径String privateKeyPath = wxPayConfig.getPrivateKeyPath();//获取私钥PrivateKey privateKey = wxPayConfig.getPrivateKey(privateKeyPath);System.out.println(privateKey);}}

5.3 获取签名验证器和HttpClient

通过商户的公钥(微信平台的证书,防止被造假)来验证签名

new WechatPay2Credentials(merchantId, new PrivateKeySigner(merchantSerialNumber, merchantPrivateKey)),

代码参数分别为

  • merchantId 商户id
  • merchantSerialNumber 商户序列号
  • merchantPrivateKey 商户私钥

具体在配置类中添加一个方法
具体实现为

一启动就自动实现,而且不需要人为,所以通过@bean进行注入

使用定时的更新签名验证器还需要结合一个对称加密apiV3Key.getBytes(StandardCharsets.UTF_8)

/*** 获取签名验证器* @return*/
@Bean
public ScheduledUpdateCertificatesVerifier getVerifier(){log.info("获取签名验证器");//获取商户私钥PrivateKey privateKey = getPrivateKey(privateKeyPath);//私钥签名对象PrivateKeySigner privateKeySigner = new PrivateKeySigner(mchSerialNo, privateKey);//身份认证对象WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, privateKeySigner);// 使用定时更新的签名验证器,不需要传入证书ScheduledUpdateCertificatesVerifier verifier = new ScheduledUpdateCertificatesVerifier(wechatPay2Credentials,apiV3Key.getBytes(StandardCharsets.UTF_8));return verifier;
}/*** 获取http请求对象* @param verifier* @return*/
@Bean(name = "wxPayClient")
public CloseableHttpClient getWxPayClient(ScheduledUpdateCertificatesVerifier verifier){log.info("获取httpClient");//获取商户私钥PrivateKey privateKey = getPrivateKey(privateKeyPath);WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create().withMerchant(mchId, mchSerialNo, privateKey).withValidator(new WechatPay2Validator(verifier));// ... 接下来,你仍然可以通过builder设置各种参数,来配置你的HttpClient// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新CloseableHttpClient httpClient = builder.build();return httpClient;
}

5.5 API字典和相关工具

添加一个json的依赖包

因为微信支付的api v3 要使用json作为消息体的数据交互格式

<!--json处理器-->
<dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId>
</dependency>

具体各个功能都需要调用API接口

具体的接口地址可以通过这个网址查询
Native下单API

为了应用的时候写成常量的形式或者枚举的形式

所以弄了一个枚举的类

  • 分别为支付宝和微信以及成员变量
    因为成员变量是final,不能改变,所以定义了一个@Getter,而没有setter的注解
@AllArgsConstructor
@Getter
public enum PayType {/*** 微信*/WXPAY("微信"),/*** 支付宝*/ALIPAY("支付宝");/*** 类型*/private final String type;
}
  • 订单状态的支付有如下的枚举类
@AllArgsConstructor
@Getter
public enum OrderStatus {/*** 未支付*/NOTPAY("未支付"),/*** 支付成功*/SUCCESS("支付成功"),/*** 已关闭*/CLOSED("超时已关闭"),/*** 已取消*/CANCEL("用户已取消"),/*** 退款中*/REFUND_PROCESSING("退款中"),/*** 已退款*/REFUND_SUCCESS("已退款"),/*** 退款异常*/REFUND_ABNORMAL("退款异常");/*** 类型*/private final String type;
}

以上两部分都是用户和商户平台的枚举类
下面商户和微信的支付平台的枚举类

  • 把所有订单出现的api接口、通知、退款、以及交易的api接口都出现在 枚举类

工具类

订单工具类
主要用于获取订单编号、获取退款单编号、以及获取编号

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;}
}

接收微信的http服务器之后响应服务器,这种叫回调通知
具体的通知都放到HttpServletRequest

public class HttpUtils {/*** 将通知参数转化为字符串* @param request* @return*/public static String readData(HttpServletRequest request) {BufferedReader br = null;try {StringBuilder result = new StringBuilder();br = request.getReader();for (String line; (line = br.readLine()) != null; ) {if (result.length() > 0) {result.append("\n");}result.append(line);}return result.toString();} catch (IOException e) {throw new RuntimeException(e);} finally {if (br != null) {try {br.close();} catch (IOException e) {e.printStackTrace();}}}}
}

6. Native订单

具体的流程图如图所示
工作的流程为:

  1. 用户通过点击支付按钮,在网站中会生成一笔订单发送给微信支付系统,微信支付系统确认调用后会发个二维码给网站后台,网站后台发给用户展示
  2. 用户扫描二维码的时候,会直接将其扫描成功连接发送给微信支付系统,之后验证其链接的有效性,返回给客户的一个输入密码的页面展示
  3. 用户通过输入密码提交,会直接发送给微信支付系统,之后进行验证其密码的准确性,验证成功之后会给客户一个显示支付成功的界面
  4. 付款成功之后,微信支付系统要给网站一个支付结果(回调通知,服务器给客户端直接发送),网站就会给服务器通知成功接收的情况
  5. 如果网站没有收到该通知,网站还需要发请主动的查询订单给服务器,之后服务器返回支付状态,在网站页面显示

6.1 Native下单

通过书写一个接口类

public interface WxPayService {}

接口实现类
一定要写上@Service注解

@Service
public class WxPayServiceImpl implements WxPayService {}

业务逻辑类如下

@CrossOrigin //跨域
@RestController //json的数据传输
@RequestMapping("/api/wx-pay")
@Api(tags = "网站微信支付APIv3") //swagger网址可以看到
@Slf4j //日志的输出结果
public class WxPayController {@Resourceprivate WxPayService wxPayService;/*** Native下单* @param productId* @return* @throws Exception*/@ApiOperation("调用统一下单API,生成支付二维码")@PostMapping("/native/{productId}")public R nativePay(@PathVariable Long productId) throws Exception {log.info("发起支付请求 v3");//返回支付二维码连接和订单号Map<String, Object> map = wxPayService.nativePay(productId);return R.ok().setData(map);}}

业务逻辑类需要书写的方法需要通过接口类和实现类进行实时补充

顺便补充一下关于返回的值可以使用链式,R.ok().setData(map);
则需要在R这个类上使用链式 的注解类@Accessors(chain = true),之后所有的返回值都可以进行链式操作

微信支付开发,基于SpringBoot+Vue架构的Java在线支付项目相关推荐

  1. 基于SpringBoot+Vue车牌识别的智能停车场项目源码

    List item ##基于SpringBoot+Vue车牌识别的智能停车场项目项目说明 智能停车场管理系统在住宅小区.大厦.单位的应用越来越普遍.而人们对停车场管理的要求也越来越高,智能化程度也越来 ...

  2. 超详细!4小时开发一个SpringBoot+vue前后端分离博客项目!!

    小Hub领读: 前后端分离的博客项目终于出来啦,真是花了好多心思录制咧.文末直接进入B站看视频哈! 作者:吕一明 项目代码:https://github.com/MarkerHub/vueblog 项 ...

  3. 基于Springboot vue前后端分离在线培训考试系统源码

    # 云帆培训考试系统 管理账号:admin/admin 学员账号:person/person # 介绍 一款多角色在线培训考试系统,系统集成了用户管理.角色管理.部门管理.题库管理.试题管理.试题导入 ...

  4. java基于SpringBoot+Vue+nodejs的演唱会话剧娱乐项目售票系统 element

    休闲娱乐代理售票系统能够通过互联网得到广泛的.全面的宣传,让尽可能多的用户了解和熟知休闲娱乐代理售票系统的便捷高效,不仅为群众提供了服务,而且也推广了自己,让更多的群众了解自己.对于休闲娱乐代理售票而 ...

  5. 基于Springboot+VUE框架开发的企业微信SCRM系统

    应用介绍 基于Springboot+ vue框架开发的企业微信SCRM 系统是一款基于人工智能的企业微信SCRM系统,企业微信SCRM系统基于企业微信开放能力,不仅集成了企微基础的客户管理和后台管理功 ...

  6. 【毕业设计】基于springboot + vue微信小程序商城

    目录 前言 创新点/亮点✨ 毕设目录 一.视频展示 二.系统介绍 三.项目地址 四.运行环境 五.设计模块 ①前台 ②后台 六.系统功能模块结构图 七. 准备阶段 ①使用真实支付 ②使用模拟支付 八. ...

  7. 基于 SpringBoot + Vue 框架开发的网页版聊天室项目

    ‍ ‍简介 微言聊天室是基于前后端分离,采用SpringBoot+Vue框架开发的网页版聊天室.使用了Spring Security安全框架进行密码的加密存储和登录登出等逻辑的处理,以WebSocke ...

  8. 基于SpringBoot vue的茶叶商城平台源码和论文含支付宝沙箱支付

    此项目是前后端分离的 后台项目:shop 前端项目:Vue-shop 后端项目启动步骤: 1.先把sql导入数据库 2.把后台项目导入编辑器 3.修改数据库配置 4.启动项目   前端项目启动步骤: ...

  9. 基于SpringBoot vue的电脑商城平台源码和论文含支付宝沙箱支付

    演示视频: 基于SpringBoot vue的电脑商城平台源码和论文含支付宝沙箱支付演示视频 支付宝沙箱: package com.java.controller;import java.util.* ...

最新文章

  1. 电信的 DNS 服务器地址
  2. 如何列出更改了特定文件的所有提交?
  3. 二元运算符的运算符重载
  4. STL 中的链表排序
  5. HDU 4812 D Tree (点分治) (2013ACM/ICPC亚洲区南京站现场赛)
  6. javaSE学习 访问控制
  7. Unity3d + UGUI 的多分辨率适配
  8. HDU-ZZY的爱好
  9. CSDN资源共享规范
  10. 求2+22+222+2222+22222
  11. 醉袖迎风受落花——好代码的10条认知
  12. QIIME 2基因云,登10分JHM
  13. [辩论]以成败轮英雄是可取的——正方一辩稿
  14. linux 拼图游戏,王牌拼图红包版
  15. 机器学习数据预处理----分类型文字数据的处理
  16. 怎样为计算机创建一个新的用户名,如何创建电脑用户名 电脑用户名是什么怎么修改...
  17. 如何进行期货日内趋势量化交易系统的设计?
  18. 电子元器件品牌及其代理商
  19. Windows驱动_WSK驱动之二WSK的操作
  20. 基于伯努利原理的速度监测芯片可用于天然气管道泄露检测

热门文章

  1. easyExcel应用
  2. PMP第5章知识点回顾,练习题
  3. linux 快速复制大量文件
  4. 基于gazebo实现多无人车的编队仿真(一)
  5. RecyclerView自定义Grid(网格)布局分割线
  6. 分享几款超好用的 REST API 工具
  7. Qt自带例子:AnalogClock ,增加了秒针
  8. 天虹迷你主机装linux,极简天虹迷你主机,小身材高性能,你的生活好搭档
  9. JavaScript如何实现多线程?
  10. C++ const 和 constexpr 的用法和区别