赞
踩
微信支付的学习链接
:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1
一、数据库准备
t_order表 主要完成订单查询
/* Navicat Premium Data Transfer Source Server : Michinaish Source Server Type : MySQL Source Server Version : 80011 Source Host : localhost:3306 Source Schema : wechat Target Server Type : MySQL Target Server Version : 80011 File Encoding : 65001 Date: 16/08/2022 19:52:38 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for t_order -- ---------------------------- DROP TABLE IF EXISTS `t_order`; CREATE TABLE `t_order` ( `id` char(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `order_no` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '订单号', `course_id` varchar(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '课程id', `course_title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '课程名称', `course_cover` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '课程封面', `teacher_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '讲师名称', `member_id` varchar(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '会员id', `nickname` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '会员昵称', `mobile` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '会员手机', `total_fee` decimal(10, 2) NULL DEFAULT 0.01 COMMENT '订单金额(分)', `pay_type` tinyint(3) NULL DEFAULT NULL COMMENT '支付类型(0:微信 1:支付宝)', `status` tinyint(3) NULL DEFAULT NULL COMMENT '订单状态(0:未支付 1:已支付)', `is_deleted` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '逻辑删除 1(true)已删除, 0(false)未删除', `gmt_create` datetime(0) NOT NULL COMMENT '创建时间', `gmt_modified` datetime(0) NOT NULL COMMENT '更新时间', PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `ux_order_no`(`order_no`) USING BTREE, INDEX `idx_course_id`(`course_id`) USING BTREE, INDEX `idx_member_id`(`member_id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '订单' ROW_FORMAT = Compact; -- ---------------------------- -- Records of t_order -- ---------------------------- INSERT INTO `t_order` VALUES ('0195f142a5824e0b88f', 'c60801fbdd2d45f9bc6', '1408424998648799234', 'Java初中级系统架构师组合套餐课(含12门课程)', 'https://kk-books.oss-cn-hangzhou.aliyuncs.com/44df362b-8d51-43a9-b823-090b02a3f2e8.jpg', '张飞', '1402269617551667201', '仲梦君', '15092182775', 32.00, 1, 0, 0, '2021-06-25 23:03:35', '2021-06-25 23:03:35'); INSERT INTO `t_order` VALUES ('21e04d165a324e59b96', '0322b37415384df0bbf', '1408421906918268930', '从零学习netty网络IO通讯开发视频教程', 'https://kk-books.oss-cn-hangzhou.aliyuncs.com/7b4a1bc6-b016-4afa-84c2-9ecfa0fae14d.jpg', '张飞', '1306495996639842305', '邱成相', '15092182541', 120.00, 1, 1, 0, '2020-06-25 23:02:27', '2020-06-25 23:02:27'); INSERT INTO `t_order` VALUES ('383714ba15e9474eb1a', 'e334ce2a6b1d4bc6936', '1408411851292532738', '姜维自传', 'https://kk-books.oss-cn-hangzhou.aliyuncs.com/8f731951-d606-4b86-8d4d-1cea38ee39f5.jpg', '姜维', '1408590478277685250', '李白', '15972331424', 0.01, 0, 0, 0, '2021-06-26 09:08:56', '2021-06-26 09:08:56'); INSERT INTO `t_order` VALUES ('39a3553e85bb4d69894', '9de332298489407fa81', '1408413427792994305', '成功的秘诀', 'https://kk-books.oss-cn-hangzhou.aliyuncs.com/03fa648e-a619-4500-a832-4750b3fa44ec.jpg', '张飞', '1402269617551667201', '仲梦君', '15092182775', 20.00, 0, 1, 0, '2021-06-25 23:09:34', '2021-06-25 23:09:50'); INSERT INTO `t_order` VALUES ('3fbd422bd60a4614a3b', '3d2e34a108174a67aba', '1408410177668767745', '水淹七军', 'https://kk-books.oss-cn-hangzhou.aliyuncs.com/74b7e90d-8463-4801-bdf8-52efd9cb6e41.jpg', '关羽', '1448200763102928897', NULL, '15660773278', 0.01, 0, 0, 0, '2021-10-13 16:17:05', '2021-10-13 16:17:05'); INSERT INTO `t_order` VALUES ('699aba8a2753439eb6a', '858c6dc73bb84c898a5', '1408409971229319170', '大白话领域驱动设计', 'https://kk-books.oss-cn-hangzhou.aliyuncs.com/5ae6a380-dbd6-4e74-8c99-a8c2ede79455.jpg', '张飞', '1408590478277685250', '李白', '15972331424', 0.01, 0, 1, 0, '2021-06-26 08:59:31', '2021-06-26 08:59:47'); INSERT INTO `t_order` VALUES ('7951387ce957484c80c', '2e4a952c118b4c47a79', '1408410177668767745', '水淹七军', 'https://kk-books.oss-cn-hangzhou.aliyuncs.com/74b7e90d-8463-4801-bdf8-52efd9cb6e41.jpg', '关羽', '1402268479037206530', '舒隆振', '15092182328', 0.01, 0, 1, 0, '2021-06-25 23:22:56', '2021-06-25 23:24:02'); INSERT INTO `t_order` VALUES ('9de56a01d7fb4a9895a', '7ff948d22cf04e61a06', '1408411851292532738', '姜维自传', 'https://kk-books.oss-cn-hangzhou.aliyuncs.com/8f731951-d606-4b86-8d4d-1cea38ee39f5.jpg', '姜维', '1448200763102928897', NULL, '15660773278', 0.01, 0, 0, 0, '2021-10-13 16:37:28', '2021-10-13 16:38:20'); INSERT INTO `t_order` VALUES ('b25d3987e7e94092b53', 'da27dfff1ae440c2aed', '1408411851292532738', '姜维自传', 'https://kk-books.oss-cn-hangzhou.aliyuncs.com/8f731951-d606-4b86-8d4d-1cea38ee39f5.jpg', '姜维', '1306495996639842305', '邱成相', '15092182541', 100.00, 0, 0, 0, '2019-06-25 21:54:13', '2019-06-25 21:54:13'); INSERT INTO `t_order` VALUES ('b9d4382ae2d84c568f9', '67164fb9916a4209876', '1408410177668767745', '水淹七军', 'https://kk-books.oss-cn-hangzhou.aliyuncs.com/74b7e90d-8463-4801-bdf8-52efd9cb6e41.jpg', '关羽', '1406792661091491841', '景晨曦', '15007124873', 10.00, 0, 0, 0, '2021-06-25 23:09:51', '2021-06-25 23:10:13'); INSERT INTO `t_order` VALUES ('c1fddde4bdae4ad68a6', 'def097eeafe44d7b8dd', '1408425438857781250', '亿级电商微服务优惠劵系统全实现', 'https://kk-books.oss-cn-hangzhou.aliyuncs.com/08a1a97e-a059-4ed7-a026-131890a4700f.JPG', '张飞', '1402269617551667201', '仲梦君', '15092182775', 0.01, 0, 0, 0, '2021-06-25 23:11:04', '2021-06-25 23:11:04'); INSERT INTO `t_order` VALUES ('dbad9d7063ab47a9b8b', '821d7109fa6d4520982', '1408409971229319170', '大白话领域驱动设计', 'https://kk-books.oss-cn-hangzhou.aliyuncs.com/5ae6a380-dbd6-4e74-8c99-a8c2ede79455.jpg', '张飞', '1448200763102928897', NULL, '15660773278', 211.00, 1, 0, 0, '2021-10-13 16:16:42', '2021-10-13 16:16:42'); INSERT INTO `t_order` VALUES ('e5f80e6712894b8793c', '28d54a53bdf14c3c853', '1408409971229319170', '大白话领域驱动设计', 'https://kk-books.oss-cn-hangzhou.aliyuncs.com/5ae6a380-dbd6-4e74-8c99-a8c2ede79455.jpg', '张飞', '1402269617551667201', '仲梦君', '15092182775', 210.00, 0, 0, 0, '2018-06-25 21:54:13', '2018-06-25 21:54:13'); INSERT INTO `t_order` VALUES ('ea744617fe8d4112796', 'e334ce2a6b1c4bc6018', '1408411851292532738', '姜维自传', 'https://kk-books.oss-cn-hangzhou.aliyuncs.com/8f731951-d606-4b86-8d4d-1cea38ee39f5.jpg', '姜维', '1306147989314703362', '木白', '15700085997', 0.01, 0, 0, 0, '2021-10-27 17:54:32', '2022-08-14 17:27:26'); SET FOREIGN_KEY_CHECKS = 1;
t_pay_log 主要是用于支付成功后 记录显示
/* Navicat Premium Data Transfer Source Server : Michinaish Source Server Type : MySQL Source Server Version : 80011 Source Host : localhost:3306 Source Schema : wechat Target Server Type : MySQL Target Server Version : 80011 File Encoding : 65001 Date: 16/08/2022 19:52:45 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for t_pay_log -- ---------------------------- DROP TABLE IF EXISTS `t_pay_log`; CREATE TABLE `t_pay_log` ( `id` char(19) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `order_no` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '订单号', `pay_time` datetime(0) NULL DEFAULT NULL COMMENT '支付完成时间', `total_fee` decimal(10, 2) NULL DEFAULT 0.01 COMMENT '支付金额(分)', `transaction_id` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '交易流水号', `trade_state` char(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '交易状态', `pay_type` tinyint(3) NOT NULL DEFAULT 0 COMMENT '支付类型(0:微信 1:支付宝)', `attr` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '其他属性', `is_deleted` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '逻辑删除 1(true)已删除, 0(false)未删除', `gmt_create` datetime(0) NOT NULL COMMENT '创建时间', `gmt_modified` datetime(0) NOT NULL COMMENT '更新时间', PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `uk_order_no`(`order_no`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '支付日志表' ROW_FORMAT = Compact; SET FOREIGN_KEY_CHECKS = 1;
二、后端准备
(1)配置application.properities
#连接数据库 server.port=8999 spring.datasource.druid.url=jdbc:mysql://localhost:3306/wechat?serverTimezone=Asia/Shanghai spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.druid.username=root spring.datasource.druid.password=root #初始化的个数 spring.datasource.druid.initial-size=5 # 最大活跃数 spring.datasource.druid.max-active=10 # 最大等待时间 spring.datasource.druid.max-wait=3000 # 最小的闲置个数 spring.datasource.druid.min-idle=5 # 微信的appid 商家id 密钥---填上自己的就行(无法申请因为需要营业执照) weixin.appid= weixin.mch_id= weixin.api_key=
(2)在pom.xml引入依赖
这里可以使自己的springboot版本降低会比较稳定
<dependencies> <!--微信依赖--> <dependency> <groupId>repMaven.com.github.wxpay</groupId> <artifactId>wxpay-sdk</artifactId> <version>0.0.3</version> </dependency> <!--Java端发送请求--> <dependency> <groupId>repMaven.org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.3</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.8</version> </dependency> <dependency> <groupId>com.spring4all</groupId> <artifactId>swagger-spring-boot-starter</artifactId> <version>1.9.1.RELEASE</version> </dependency> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> <version>1.7.8</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.5.1</version> </dependency> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.28</version> <scope>compile</scope> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </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> </dependency> </dependencies>
(3)使用代码生成器 对俩表自动生成
代码生成器配置类为:
public class GeneCode { public static void main(String[] args) { //数据库配置 String url="jdbc:mysql://localhost:3306/wechat?serverTimezone=Asia/Shanghai"; //要自动生成的表名 多个表之间使用逗号隔开 String[] tables = {"t_order","t_pay_log"}; //获取本项目的路径 String projectPath = System.getProperty("user.dir"); //包项目路径 String outputDir =projectPath+"/src/main/java"; //xml文件路径 String outputDirMapper = projectPath+"/src/main/resources/mapper"; //快速创建 FastAutoGenerator.create(url, "root", "root") .globalConfig(builder -> { builder.author("wx") // 设置作者 .enableSwagger() // 开启 swagger 模式 .fileOverride() // 覆盖已生成文件 .outputDir(outputDir); // 指定输出目录 }) .packageConfig(builder -> { builder.parent("com.wx") // 设置父包名 .pathInfo(Collections.singletonMap(OutputFile.mapperXml, outputDirMapper)); // 设置mapperXml生成路径 }) .strategyConfig(builder -> { builder.addInclude(tables) // 设置需要生成的表名 .addTablePrefix("t_"); // 设置过滤表前缀,多个前缀可用逗号隔开 }) .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板 .execute(); } }
(4)配置类
用于Java端模拟浏览器
public class HttpClient { private String url; private Map<String, String> param; private int statusCode; private String content; private String xmlParam; private boolean isHttps; public boolean isHttps() { return isHttps; } public void setHttps(boolean isHttps) { this.isHttps = isHttps; } public String getXmlParam() { return xmlParam; } public void setXmlParam(String xmlParam) { this.xmlParam = xmlParam; } public HttpClient(String url, Map<String, String> param) { this.url = url; this.param = param; } public HttpClient(String url) { this.url = url; } public void setParameter(Map<String, String> map) { param = map; } public void addParameter(String key, String value) { if (param == null) param = new HashMap<String, String>(); param.put(key, value); } public void post() throws ClientProtocolException, IOException { HttpPost http = new HttpPost(url); setEntity(http); execute(http); } public void put() throws ClientProtocolException, IOException { HttpPut http = new HttpPut(url); setEntity(http); execute(http); } public void get() throws ClientProtocolException, IOException { if (param != null) { StringBuilder url = new StringBuilder(this.url); boolean isFirst = true; for (String key : param.keySet()) { if (isFirst) url.append("?"); else url.append("&"); url.append(key).append("=").append(param.get(key)); } this.url = url.toString(); } HttpGet http = new HttpGet(url); execute(http); } /** * set http post,put param */ private void setEntity(HttpEntityEnclosingRequestBase http) { if (param != null) { List<NameValuePair> nvps = new LinkedList<NameValuePair>(); for (String key : param.keySet()) nvps.add(new BasicNameValuePair(key, param.get(key))); // 参数 http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 设置参数 } if (xmlParam != null) { http.setEntity(new StringEntity(xmlParam, Consts.UTF_8)); } } private void execute(HttpUriRequest http) throws ClientProtocolException, IOException { CloseableHttpClient httpClient = null; try { if (isHttps) { SSLContext sslContext = new SSLContextBuilder() .loadTrustMaterial(null, new TrustStrategy() { // 信任所有 public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }).build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslContext); httpClient = HttpClients.custom().setSSLSocketFactory(sslsf) .build(); } else { httpClient = HttpClients.createDefault(); } CloseableHttpResponse response = httpClient.execute(http); try { if (response != null) { if (response.getStatusLine() != null) statusCode = response.getStatusLine().getStatusCode(); HttpEntity entity = response.getEntity(); // 响应内容 content = EntityUtils.toString(entity, Consts.UTF_8); } } finally { response.close(); } } catch (Exception e) { e.printStackTrace(); } finally { httpClient.close(); } } public int getStatusCode() { return statusCode; } public String getContent() throws ParseException, IOException { return content; } }
(5)添加和修改实体类
Result类用于返回给前端
@AllArgsConstructor
@NoArgsConstructor
@Data
@ApiModel(value = "统一json数据")
public class Result {
@ApiModelProperty("状态码2000表示成功 5000表示失败")
private Integer code;
@ApiModelProperty("响应的消息内容")
private String msg;
@ApiModelProperty("响应的数据")
private Object data;
}
修改实体类 主要用于mp 可以自动注入时间
package com.wx.entity; import com.baomidou.mybatisplus.annotation.TableName; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDateTime; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * <p> * 订单 * </p> * * @author wx * @since 2022-08-13 */ @TableName("t_order") @ApiModel(value = "Order对象", description = "订单") @Data @AllArgsConstructor @NoArgsConstructor public class Order implements Serializable { private static final long serialVersionUID = 1L; private String id; @ApiModelProperty("订单号") private String orderNo; @ApiModelProperty("课程id") private String courseId; @ApiModelProperty("课程名称") private String courseTitle; @ApiModelProperty("课程封面") private String courseCover; @ApiModelProperty("讲师名称") private String teacherName; @ApiModelProperty("会员id") private String memberId; @ApiModelProperty("会员昵称") private String nickname; @ApiModelProperty("会员手机") private String mobile; @ApiModelProperty("订单金额(分)") private BigDecimal totalFee; @ApiModelProperty("支付类型(0:微信 1:支付宝)") private Integer payType; @ApiModelProperty("订单状态(0:未支付 1:已支付)") private Integer status; @ApiModelProperty("逻辑删除 1(true)已删除, 0(false)未删除") private Boolean isDeleted; @ApiModelProperty("创建时间") private LocalDateTime gmtCreate; @ApiModelProperty("更新时间") private LocalDateTime gmtModified; }
package com.wx.entity; import com.baomidou.mybatisplus.annotation.*; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDateTime; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * <p> * 支付日志表 * </p> * * @author wx * @since 2022-08-13 */ @TableName("t_pay_log") @ApiModel(value = "PayLog对象", description = "支付日志表") @Data @AllArgsConstructor @NoArgsConstructor public class PayLog implements Serializable { private static final long serialVersionUID = 1L; @TableId(value = "id",type = IdType.ASSIGN_ID) private Long id; @ApiModelProperty("订单号") private String orderNo; @ApiModelProperty("支付完成时间") @JsonDeserialize(using = LocalDateTimeDeserializer.class) @JsonSerialize(using = LocalDateTimeSerializer.class) @TableField(fill = FieldFill.INSERT) private LocalDateTime payTime; @ApiModelProperty("支付金额(分)") private BigDecimal totalFee; @ApiModelProperty("交易流水号") private String transactionId; @ApiModelProperty("交易状态") private String tradeState; @ApiModelProperty("支付类型(0:微信 1:支付宝)") private Integer payType; @ApiModelProperty("其他属性") private String attr; @ApiModelProperty("逻辑删除 1(true)已删除, 0(false)未删除") @TableLogic private Boolean isDeleted; @ApiModelProperty("创建时间") @JsonDeserialize(using = LocalDateTimeDeserializer.class) @JsonSerialize(using = LocalDateTimeSerializer.class) @TableField(fill = FieldFill.INSERT) private LocalDateTime gmtCreate; @ApiModelProperty("更新时间") @JsonDeserialize(using = LocalDateTimeDeserializer.class) @JsonSerialize(using = LocalDateTimeSerializer.class) @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime gmtModified; }
(6)配置自动修改和创建时间的配置文件
package com.wx.config; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; import java.time.LocalDateTime; @Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill ...."); this.strictInsertFill(metaObject, "gmtCreate", LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, "gmtModified", LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, "payTime", LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, "isDeleted", Boolean.class, false); System.out.println("我执行了"); } @Override public void updateFill(MetaObject metaObject) { log.info("start update fill ...."); // 默认提供的strictUpdateFill为有值不覆盖, gmtModified需要覆盖,利用通用塞值的方法填充 this.setFieldValByName("gmtModified", LocalDateTime.now(), metaObject); } }
(7)修改控制层代码–添加业务
@RestController @RequestMapping("/order") public class OrderController { @Autowired private IOrderService orderService; @PostMapping("createQRCode/{orderNo}") public Result createQRCode(@PathVariable String orderNo){ return orderService.createQRCode(orderNo); } @PostMapping("queryPayStatus/{orderNo}") public Result queryPayStatus(@PathVariable String orderNo){ return orderService.queryPayStatus(orderNo); } }
(8)修改service及其实现类
package com.wx.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.github.wxpay.sdk.WXPayUtil; import com.wx.entity.Order; import com.wx.entity.PayLog; import com.wx.mapper.OrderMapper; import com.wx.mapper.PayLogMapper; import com.wx.service.IOrderService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.wx.utils.HttpClient; import com.wx.vo.Result; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; /** * <p> * 订单 服务实现类 * </p> * * @author wx * @since 2022-08-13 */ @Service public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService { @Autowired private OrderMapper orderMapper; /*获取微信的appid*/ @Value("${weixin.appid}") private String appId; /*获取配置文件中的商家id*/ @Value("${weixin.mch_id}") private String mchId; /*获取密钥*/ @Value("${weixin.api_key}") private String apiKey; @Autowired private PayLogMapper payLogMapper; /*创建订单*/ @Override public Result createQRCode(String orderNo) { /*查询orderNo的订单信息*/ QueryWrapper wrapper = new QueryWrapper(); wrapper.eq("order_no", orderNo); wrapper.eq("status", 0); Order order = orderMapper.selectOne(wrapper); /*不为空 才能进行业务操作*/ if (order != null) { try { //获取下单的接口url HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder"); //设置支持https请求 client.setHttps(true); /*以下的字段是必填字段 * https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1 * 该链接中对必填字段有描述 * */ Map<String, String> parms = new HashMap<>(); parms.put("appid", appId); parms.put("mch_id", mchId); parms.put("nonce_str", WXPayUtil.generateNonceStr()); parms.put("body", order.getCourseTitle()); parms.put("out_trade_no", orderNo); parms.put("total_fee", (order.getTotalFee().multiply(new BigDecimal(100))).longValue() + ""); parms.put("spbill_create_ip", "127.0.0.1"); parms.put("notify_url", "http://localhost:8999/pay/back"); parms.put("trade_type","NATIVE"); client.setXmlParam(WXPayUtil.generateSignedXml(parms, apiKey)); /*post请求*/ client.post(); String content = client.getContent(); /*得到的content其实是xml格式 所以要转为map格式*/ Map<String,String> map = WXPayUtil.xmlToMap(content); /*若返回值成功 就会有一个codeurl 该值返回给前端会通过vue将连接转为二维码*/ if(map.get("result_code").equals("SUCCESS")){ /*将需要的值返回给前端*/ Map<String,Object> result = new HashMap<>(); result.put("codeUrl",map.get("code_url")); result.put("price",order.getTotalFee()); result.put("orderNo",order.getOrderNo()); return new Result(2000,"生成二维码成功",result); } } catch (Exception e) { e.printStackTrace(); } } return new Result(5000, "创建失败", null); } /*创建订单后 要查询订单的状态*/ @Override @Transactional public Result queryPayStatus(String orderNo) { try { /*https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_2 注意查询状态和获取订单的url不一样 * * */ HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery"); client.setHttps(true); Map<String, String> parms = new HashMap<>(); parms.put("appid", appId); parms.put("mch_id", mchId); parms.put("out_trade_no", orderNo); parms.put("nonce_str", WXPayUtil.generateNonceStr()); client.setXmlParam(WXPayUtil.generateSignedXml(parms, apiKey)); client.post(); String content = client.getContent(); System.out.println(content); Map<String,String> map = WXPayUtil.xmlToMap(content); String transactionId = map.get("out_trade_no"); /*支付成功就会得到交易状态 若成功继续执行*/ if(map.get("trade_state").equals("SUCCESS")){ Order order = new Order(); /*成功后改变当前订单的状态*/ order.setStatus(1); order.setGmtModified(LocalDateTime.now()); QueryWrapper<Order> wrapper = new QueryWrapper<>(); wrapper.eq("order_no",orderNo); wrapper.eq("status",0); Order one = orderMapper.selectOne(wrapper); orderMapper.update(order,wrapper); /*支付成功后修改t_pay_log*/ String tradeState = map.get("trade_state"); PayLog payLog = new PayLog(); payLog.setOrderNo(orderNo); payLog.setPayType(one.getPayType()); payLog.setTotalFee(one.getTotalFee()); payLog.setTransactionId(transactionId); payLog.setTradeState(tradeState); payLog.setIsDeleted(false); payLogMapper.insert(payLog); return new Result(2000,"支付成功",null); } } catch (Exception e) { e.printStackTrace(); } return new Result(5000,"支付失败",null); } }
前后端分离需要解决跨域问题
package com.wx.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; @Configuration public class CorsConfig { // 当前跨域请求最大有效时长。这里默认1天 private static final long MAX_AGE = 24 * 60 * 60; @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址 corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头 corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法 corsConfiguration.setMaxAge(MAX_AGE); source.registerCorsConfiguration("/**", corsConfiguration); // 4 对接口配置跨域设置 return new CorsFilter(source); } }
三、前端准备
前端需要引入 vue-qr依赖
(1)前端主页面
<template> <div> <el-button type="primary" @click="pay">支付</el-button> <el-dialog title="收银台" :visible.sync="dialogVisible" width="30%"> <div style="text-align: center"> <p>微信支付{{payResult.price}}元</p> <div style="border: 10px solid grey;width:160px;padding:10px;margin:0px auto"> <vue-qr :text="payResult.codeUrl" colorLight="#fff" :size="160" margin="0" :logo-src="require('../assets/3.webp')" > </vue-qr> </div> <el-divider></el-divider> <div style="font-size: 13px"> 提示:<br> 支付成功前请勿手动关闭页面<br> 二维码两个小时有效,请及时扫码支付<br> </div> </div> </el-dialog> </div> </template> <script> import vueQr from 'vue-qr' export default { components:{ vueQr }, name: "WeChatPay", data(){ return{ orderNo:"e334ce2a6b1c4bc6018", payResult:{ codeUrl:"", price:0, orderNo:'', }, dialogVisible:false, timer:"", flag:0, } }, methods:{ queryPayStatus(orderNo){ this.$http.post("/order/queryPayStatus/"+orderNo).then(result=>{ if(result.data.code===2000){ clearInterval(this.timer); this.timer=null; this.$message.success("支付成功"); this.dialogVisible = false; } }) }, pay(){ this.dialogVisible = true; /*创建订单*/ this.$http.post("order/createQRCode/"+this.orderNo).then(result=>{ if(result.data.code===2000){ this.payResult = result.data.data; /*每隔三秒查询订单的状态 是否支付*/ this.timer = setInterval(()=>{ this.queryPayStatus(this.payResult.orderNo) },3000); } }) }, } } </script> <style scoped> </style>
(2)修改main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import './plugins/element.js'
import axios from "axios";
axios.defaults.baseURL="http://localhost:8999/"
Vue.config.productionTip = false
Vue.prototype.$http=axios
new Vue({
router,
render: h => h(App)
}).$mount('#app')
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。