目录
1.微信支付的流程
2.微信的接口文档
3.新建一个spring-boot的项目
4.导入需要的依赖
5.配置application文件
6.创建一个Httpclient的工具类-默认浏览器进行远程调用
7.自动生成器--帮我们自动生成类,接口等
8. 前端代码
8.1.新建vue项目
8.1.1.打开cmd命令窗口,输入命令打开窗口
8.1.2. 新建
8.2.安装element插件和axios的依赖(省略)
8.3.引入axios和设置axios基础路径
8.4.前端页面
9.根据订单号创建二维码--后端
9.1.controller层
9.2.Iservice
9.3.service层
9.4.实体类
9.4.1.CommonResult
9.4.2.Order
10.根据订单状态查询微信支付情况
10.1.前端
10.2.后端
10.2.1.controller
10.2.2.Iservice
10.2.3.service层
1.微信支付的流程
2.微信的接口文档
https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1
3.新建一个spring-boot的项目
4.导入需要的依赖
<?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.3.12.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>springboot</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>WeChatPay</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!--微信需要的依赖--> <dependency> <groupId>com.github.wxpay</groupId> <artifactId>wxpay-sdk</artifactId> <version>0.0.3</version> </dependency> <!--java端发送的请求 在java端远程模拟浏览器能访问微信的接口--> <dependency> <groupId>repMaven.org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.3</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.31</version> </dependency> <!--mybatis-plus的依赖--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.8</version> </dependency> <!--swagger的依赖--> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> <version>1.9.6</version> </dependency> <!--spring的依赖--> <dependency> <groupId>com.spring4all</groupId> <artifactId>swagger-spring-boot-starter</artifactId> <version>1.9.1.RELEASE</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> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build></project>
5.配置application文件
server.port=8888spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.username=rootspring.datasource.druid.password=grt081141spring.datasource.druid.url=jdbc:mysql://localhost:3306/wechatpay?serverTimezone=Asia/Shanghai#微信app的id 商家的id 秘钥--我们自己没有办法申请,因为申请需要营业执照weixin.appid=wx8087d8149331d27cweixin.mch_id=1532192611weixin.api_key=Cc158380629071583806290715838062
6.创建一个Httpclient的工具类-默认浏览器进行远程调用
package springboot.util;import org.apache.http.Consts;import org.apache.http.HttpEntity;import org.apache.http.NameValuePair;import org.apache.http.client.ClientProtocolException;import org.apache.http.client.entity.UrlEncodedFormEntity;import org.apache.http.client.methods.*;import org.apache.http.conn.ssl.SSLConnectionSocketFactory;import org.apache.http.conn.ssl.SSLContextBuilder;import org.apache.http.conn.ssl.TrustStrategy;import org.apache.http.entity.StringEntity;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.message.BasicNameValuePair;import org.apache.http.util.EntityUtils;import javax.net.ssl.SSLContext;import java.io.IOException;import java.security.cert.CertificateException;import java.security.cert.X509Certificate;import java.text.ParseException;import java.util.HashMap;import java.util.LinkedList;import java.util.List;import java.util.Map;/** * http请求客户端 * * @author 必须引入httpclient的依赖:在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; }}
7.自动生成器--帮我们自动生成类,接口等
public class Generator { public static void main(String[] args) { FastAutoGenerator.create("jdbc:mysql://localhost:3306/wechatpay?serverTimezone=Asia/Shanghai", "root", "grt081141" + "") .globalConfig(builder -> { builder.author("guan") // 设置作者 .enableSwagger() // 开启 swagger 模式 .fileOverride() // 覆盖已生成文件 .outputDir(".\\src\\main\\java\\"); // 指定输出目录 }) .packageConfig(builder -> { builder.parent("springboot") // 设置父包名 .moduleName("system") // 设置父包模块名 .pathInfo(Collections.singletonMap(OutputFile.xml, "src\\main\\resources\\mapper\\")); // 设置mapperXml生成路径 }) .strategyConfig(builder -> { builder.addInclude("t_order")// 设置需要生成的表名 .addTablePrefix("t_"); // 设置过滤表前缀 }) .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板 .execute(); }
8. 前端代码
8.1.新建vue项目
8.1.1.打开cmd命令窗口,输入命令打开窗口
vue ui
8.1.2. 新建
8.2.安装element插件和axios的依赖(省略)
8.3.引入axios和设置axios基础路径
//引入axiosimport axios from "axios";Vue.config.productionTip = false//设置axios基础路径axios.defaults.baseURL="http://localhost:8888"Vue.prototype.axios=axios;
8.4.前端页面
<template> <div id="app"> <el-button type="primary" @click="pay">支付</el-button> <!--二维码的弹出层--> <el-dialog title="收银台" :visible.sync="dislogVisible" width="30%"> <div style="text-align: center"> <p>微信支付{{payResult.price}}元</p> <div style="border: 1px solid #f3f3f3; width: 220px;padding: 0px;margin: 0px auto"> <!--使用vue-qr--> <vue-qr :text="payResult.codeUrl" :margin="0" colorDark="green" :logo="require('@/assets/logo.png')" colorLight="#fff" :size="200"> </vue-qr> </div> </div> <el-divider></el-divider> <div style="font-size: 13px;"> 提示:<br> 二维码两小时内有效,请及时扫码支付<br> </div> </el-dialog> </div></template><script> //引入vue-qr import vueQr from 'vue-qr' export default { name: 'app', //注册vue-qr components:{ vueQr }, data(){ return{ orderNo:"c60801fbdd2d45f9adg", codeUrl:"", //定时器 timer1:"", dislogVisible:false, //得到响应的结果 payResult:{ //价格 price:0, //二维码路径 借助vue-qr 可以把二维码地址转为二维码图片 codeUrl:"", orderNo:"", } } }, methods:{ pay(){ this.dislogVisible=true; this.axios.post("/system/order/createNavite/"+this.orderNo).then(result=>{ if(result.data.code===2000){ console.log(result) this.payResult=result.data.data; //设置一个定时器任务,每隔3秒调用一次 this.timer1=setInterval(()=>{ this.queryPayStatus(this.payResult.orderNo) },3000); } }) } } }</script><style></style>
9.根据订单号创建二维码--后端
9.1.controller层
@CrossOrigin@RestController@RequestMapping("/system/order")public class OrderController { //自动注入 @Autowired private IOrderService orderService; //根据订单号创建二维码 @RequestMapping("createNavite/{orderNo}") public CommonResult createNative(@PathVariable String orderNo){ return orderService.createNative(orderNo); } }
9.2.Iservice
CommonResult createNative(String orderNo);
9.3.service层
@Servicepublic class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService { @Autowired private OrderMapper orderMapper; @Value("${weixin.appid}") private String appId; @Value("${weixin.mch_id}") private String mchId; @Value("${weixin.api_key}") private String apikey; @Override public CommonResult createNative(String orderNo) { //1.根据订单号查询出订单信息 QueryWrapper wrapper=new QueryWrapper(); //前端传过来的订单号跟数据库中的订单号一致 wrapper.eq("order_no",orderNo); //订单状态为0 wrapper.eq("status",0); Order order=orderMapper.selectOne(wrapper); //判断订单信息不为空 if (order != null) { try { //接口里面的参数要的是xml类型 //设置请求的参数个数格式为xml格式 //将请求参数封装成map Map<String, String> params = new HashMap<>(); //添加公众账号Id params.put("appid", appId); //添加商品号 params.put("mch_id", mchId); //添加随机字符串--微信自带算法 params.put("nonce_str", WXPayUtil.generateNonceStr()); //添加商品描述 params.put("body", order.getCourseTitle()); //添加商品订单号 params.put("out_trade_no", orderNo); //添加标价金额 --单位是分,要转换 params.put("total_fee", new BigDecimal(0.01).multiply(new BigDecimal(100)).longValue() + ""); //添加终端ip params.put("spbill_create_ip", "127.0.0.1"); //添加通知地址 params.put("notify_url", "http://localhost:8888/pay/back"); //添加交易类型 params.put("trade_type", "NATIVE"); //创建HttpClient对象--作用远程调用 HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder"); //支持https协议 client.setHttps(true); //将map转为xml格式--设置请求的参数 client.setXmlParam(WXPayUtil.generateSignedXml(params,apikey)); //发送请求 client.post(); //获取请求响应响应的结果 String content = client.getContent(); System.out.println(content); //将String类型转换为map返货给前端 Map<String, String> map = WXPayUtil.xmlToMap(content); 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",orderNo); return new CommonResult(2000,"生成二维码",result); } }catch (Exception e){ e.printStackTrace(); } } return new CommonResult(5000,"订单失效",null); } }
9.4.实体类
9.4.1.CommonResult
@Data@NoArgsConstructor@AllArgsConstructor@ApiModel("返回同一的信息")public class CommonResult { @ApiModelProperty("状态码 2000成功,5000失败") private int code; @ApiModelProperty("信息") private String msg; @ApiModelProperty("数据") private Object data;}
9.4.2.Order
package springboot.system.entity;import com.baomidou.mybatisplus.annotation.TableName;import java.io.Serializable;import java.math.BigDecimal;import java.time.LocalDateTime;import java.util.Date;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;/** * <p> * 订单 * </p> * * @author guan * @since 2022-08-13 */@TableName("t_order")@ApiModel(value = "Order对象", description = "订单")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; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getOrderNo() { return orderNo; } public void setOrderNo(String orderNo) { this.orderNo = orderNo; } public String getCourseId() { return courseId; } public void setCourseId(String courseId) { this.courseId = courseId; } public String getCourseTitle() { return courseTitle; } public void setCourseTitle(String courseTitle) { this.courseTitle = courseTitle; } public String getCourseCover() { return courseCover; } public void setCourseCover(String courseCover) { this.courseCover = courseCover; } public String getTeacherName() { return teacherName; } public void setTeacherName(String teacherName) { this.teacherName = teacherName; } public String getMemberId() { return memberId; } public void setMemberId(String memberId) { this.memberId = memberId; } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; } public BigDecimal getTotalFee() { return totalFee; } public void setTotalFee(BigDecimal totalFee) { this.totalFee = totalFee; } public Integer getPayType() { return payType; } public void setPayType(Integer payType) { this.payType = payType; } public Integer getStatus() { return status; } public void setStatus(Integer status) { this.status = status; } public Boolean getIsDeleted() { return isDeleted; } public void setIsDeleted(Boolean isDeleted) { this.isDeleted = isDeleted; } public LocalDateTime getGmtCreate() { return gmtCreate; } public void setGmtCreate(LocalDateTime gmtCreate) { this.gmtCreate = gmtCreate; } public LocalDateTime getGmtModified() { return gmtModified; } public void setGmtModified(LocalDateTime gmtModified) { this.gmtModified = gmtModified; } @Override public String toString() { return "Order{" + "id=" + id + ", orderNo=" + orderNo + ", courseId=" + courseId + ", courseTitle=" + courseTitle + ", courseCover=" + courseCover + ", teacherName=" + teacherName + ", memberId=" + memberId + ", nickname=" + nickname + ", mobile=" + mobile + ", totalFee=" + totalFee + ", payType=" + payType + ", status=" + status + ", isDeleted=" + isDeleted + ", gmtCreate=" + gmtCreate + ", gmtModified=" + gmtModified + "}"; }}
10.根据订单状态查询微信支付情况
10.1.前端
//根据订单号查询支付状态 queryPayStatus(orderNo){ this.axios.post("system/order/queryPayStatus/"+orderNo).then(result=>{ if (result.data.code===2000){ //清除定时器 clearInterval(this.timer1) this.timer1=null; this.$message.success("支付成功") //关闭弹出层 this.dislogVisible=false; } }) },
10.2.后端
10.2.1.controller
@RequestMapping("queryPayStatus/{orderNo}") public CommonResult queryPayStatus(@PathVariable String orderNo){ return orderService.queryPayStatus(orderNo); }
10.2.2.Iservice
CommonResult queryPayStatus(String orderNo);
10.2.3.service层
@Override public CommonResult queryPayStatus(String orderNo) { //1.根据订单状态查询微信支付情况 try { HttpClient client=new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery"); //设置参数--分装成map在转为xml格式 Map<String, String> params = new HashMap<>(); //添加公众账号Id params.put("appid", appId); //添加商品号 params.put("mch_id", mchId); //添加商品订单号 params.put("out_trade_no",orderNo); //添加随机字符串 params.put("nonce_str",WXPayUtil.generateNonceStr()); //支持Https client.setHttps(true); client.setXmlParam(WXPayUtil.generateSignedXml(params,apikey)); client.post(); String content = client.getContent(); //转换为map Map<String, String> map = WXPayUtil.xmlToMap(content); if (map.get("trade_state").equals("SUCCESS")){ //1.修改订单的状态 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); orderMapper.update(order,wrapper); return new CommonResult(2000,"支付成功",null); } }catch (Exception e){ e.printStackTrace(); } return new CommonResult(5000,"支付失败",null); }