写在开始:一个搬砖程序员的随缘记录
微信支付相对其他支付,比如支付宝支付坑比较多。一直报签名失败。签名参数顺序、数据类型,加密类型这些都需要注意,用第三方的比较省心。
IJpay介绍:
聚合支付,IJPay 让支付触手可及,封装了微信支付、QQ支付、支付宝支付、京东支付、银联支付、PayPal支付等常用的支付方式以及各种常用的接口。不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。
项目整体目录:
文章目录
- 一、获取微信APP支付必须的参数
- 二、项目配置
- 1、需要引入的的jar包
- 2、application.yml
- 3、微信配置类
- 4、Swagger配置文件
- 5、微信支付业务实现相关
一、获取微信APP支付必须的参数
1、appId:微信开放平台上面的应用appid
2、mchId:微信商户号,注意这是登陆的商户平台,不是开放平台了
3、mchKey:API密钥
登录微信商户平台—>账户中心—>API安全—>设置秘钥
4、然后在微信开放平台上面的应用支付功能必须是开通的,还要绑定商户平台对应的商户号才可以
获取到上面所需要的必须参数下面就开始进行项目配置
二、项目配置
1、需要引入的的jar包
<!-- lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- swagger-ui --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.5.0</version></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.5.0</version></dependency><dependency><groupId>com.github.xiaoymin</groupId><artifactId>swagger-bootstrap-ui</artifactId><version>1.8.1</version></dependency><!-- IJPay --><dependency><groupId>com.github.javen205</groupId><artifactId>IJPay-All</artifactId><version>2.2.0</version></dependency><!--fastjson--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.7</version></dependency>
2、application.yml
wxpay:appId: # appidmchId: # 商户号mchKey: # 秘钥notifyUrl: http://127.0.0.1:8080/wxPay/wxPayNotice #微信支付回调地址
3、微信配置类
微信配置参数类
WxPayProperties.Java
package com.cn.wxpay.config;import lombok.Data;
import org.springframework.beans.factory.annotation.Value;/*** @Author: demo* @Date: 2020/9/23 15:51*/
@Data
public class WxPayProperties {/*** appid.*/@Value("${wxpay.appId}")private String appId;/*** 微信支付商户号.*/@Value("${wxpay.mchId}")private String mchId;/*** 微信支付商户密钥.*/@Value("${wxpay.mchKey}")private String mchKey;/*** 异步回调地址*/@Value("${wxpay.notifyUrl}")private String notifyUrl;
}
创建WxPayProperties的实例
WxConfig.Java
package com.cn.wxpay.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @Author: demo* @Date: 2020/9/23 15:51*/
@Configuration
public class WxConfig {@Bean("WxPayProperties")public WxPayProperties wxPayProperties(){return new WxPayProperties();}
}
4、Swagger配置文件
SwaggerConfig.Java
package com.cn.wxpay.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;/*** @Author: demo* @Date: 2020/9/23 15:51*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {@Beanpublic Docket customDocket() {return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());}private ApiInfo apiInfo() {return new ApiInfoBuilder().title("swagger RESTful APIs").description("swagger RESTful APIs").termsOfServiceUrl("http://www.test.com/").contact("xiaoymin@foxmail.com").version("1.0").build();}
}
5、微信支付业务实现相关
订单实体类
TblAutoOrderDat.Java
package com.cn.wxpay.entity;import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;import java.math.BigDecimal;
import java.util.Date;/*** @Author: demo* @Date: 2020/9/23 15:51*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "订单实体类")
public class TblAutoOrderDat {@ApiModelProperty(value = "id")private Integer id;@ApiModelProperty(value = "商品描述")private String attach;@ApiModelProperty(value = "交易类型")private String tradeType;@ApiModelProperty(value = "订单号")private String orderId;@ApiModelProperty(value = "订单金额")private BigDecimal totalFee;@ApiModelProperty(value = "微信支付订单号")private String transactionId;@ApiModelProperty(value = "支付时间")private Date payTime;@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")@ApiModelProperty(value = "创建时间")private Date createTime;@ApiModelProperty(value = "创建人")private Integer createUser;@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")@ApiModelProperty(value = "修改时间")private Date updateTime;@ApiModelProperty(value = "创建人")private Integer updateUser;@ApiModelProperty(value = "是否删除 1:已删除 0:未删除")private Boolean isDelete;
}
微信工具类
WxPayUtil.Java
package com.cn.wxpay.util;import java.util.Map;/*** @Author: demo* @Date: 2020/9/23 15:51*/
public class WxPayUtil {/*** 将map转换为xml*/public static String getMapToXml(Map<String, String> param) {StringBuilder sb = new StringBuilder();sb.append("<xml>");for (Map.Entry<String, String> entry : param.entrySet()) {sb.append("<" + entry.getKey() + ">");sb.append(entry.getValue());sb.append("</" + entry.getKey() + ">");}sb.append("</xml>");return sb.toString();}
}
IP转换类
IpKit.Java
package com.cn.wxpay.config;import javax.servlet.http.HttpServletRequest;/*** @author demo* @Date: 2020/9/23 15:51*/
public class IpKit {private final static String UNKNOWN = "unknown";public static String getRealIp(HttpServletRequest request) {String ip = request.getHeader("x-forwarded-for");if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}return ip;}public static String getRealIpV2(HttpServletRequest request) {String accessIp = request.getHeader("x-forwarded-for");if (null == accessIp) {return request.getRemoteAddr();}return accessIp;}
}
业务类
WxPayController.Java
package com.cn.wxpay.controller;import com.alibaba.fastjson.JSON;
import com.cn.wxpay.config.IpKit;
import com.cn.wxpay.config.WxPayProperties;
import com.cn.wxpay.entity.TblAutoOrderDat;
import com.cn.wxpay.util.WxPayUtil;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.enums.TradeType;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.model.UnifiedOrderModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;/*** @Author: demo* @Date: 2020/9/23 15:51*/
@RestController
@Slf4j
@RequestMapping("/wxPay")
public class WxPayController {@Autowiredprivate WxPayProperties wxPayProperties;/*** 微信APP支付** @param attach 订单描述:比如会员卡充值、商品名称* @param totalFee 支付金额* @return 微信支付返回*/@GetMapping(value = "/appPay")@ResponseBodypublic Map<String, String> appPay(HttpServletRequest request, @RequestParam("totalFee") BigDecimal totalFee, @RequestParam("attach") String attach) {String ip = IpKit.getRealIp(request);if (StringUtils.isEmpty(ip)) {ip = "127.0.0.1";}Map<String, String> params = UnifiedOrderModel.builder().appid(wxPayProperties.getAppId()).mch_id(wxPayProperties.getMchId()).nonce_str(WxPayKit.generateStr()).body(attach).attach(attach).out_trade_no(WxPayKit.generateStr()).total_fee(String.valueOf(totalFee.multiply(new BigDecimal(100)).intValue())).spbill_create_ip(ip).notify_url(wxPayProperties.getNotifyUrl()).trade_type(TradeType.APP.getTradeType()).build().createSign(wxPayProperties.getMchKey(), SignType.MD5);String xmlResult = WxPayApi.pushOrder(false, params);log.info(xmlResult);Map<String, String> result = WxPayKit.xmlToMap(xmlResult);String returnCode = result.get("return_code");String returnMsg = result.get("return_msg");if (!WxPayKit.codeIsOk(returnCode)) {log.info("错误信息:"+returnMsg);}String resultCode = result.get("result_code");if (!WxPayKit.codeIsOk(resultCode)) {log.info("错误信息:"+returnMsg);}// 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回String prepayId = result.get("prepay_id");Map<String, String> packageParams = WxPayKit.appPrepayIdCreateSign(wxPayProperties.getAppId(), wxPayProperties.getMchId(), prepayId,wxPayProperties.getMchKey(), SignType.MD5);String jsonStr = JSON.toJSONString(packageParams);log.info("返回apk的参数:" + jsonStr);return packageParams;}/*** 微信回调接口*/@PostMapping("/wxPayNotice")public String parseOrderNotifyResult(@RequestBody String xmlData) throws ParseException {Map<String, String> map = new HashMap<>();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");log.info("微信回调开始了");//这里我只进行了部分回调信息的保存,更多参数请查看微信支付官方api:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8Map<String, String> resultMap = WxPayKit.xmlToMap(xmlData);log.info("resultMap:" + resultMap);/*----------------------分割线,下面的是业务代码,根据自己业务进行修改--------------------------*///订单成功业务处理if ("SUCCESS".equals(resultMap.get("result_code"))) {// 根据resultMap处理订单业务TblAutoOrderDat tblAutoOrderDat = new TblAutoOrderDat();//订单描述,比如:会员卡充值,商品信息tblAutoOrderDat.setAttach(resultMap.get("attach"));//交易类型 比如:JSAPI、NATIVE、APPtblAutoOrderDat.setTradeType(resultMap.get("trade_type"));//商户订单号 商家生成,传给微信返回的tblAutoOrderDat.setOrderId(resultMap.get("out_trade_no"));//订单金额 订单总金额,单位为分,我这里转换成元了tblAutoOrderDat.setTotalFee(new BigDecimal(resultMap.get("total_fee")).divide(new BigDecimal(100)));//微信支付订单号tblAutoOrderDat.setTransactionId(resultMap.get("transaction_id"));//支付完成时间String newDate = resultMap.get("time_end");tblAutoOrderDat.setPayTime(sdf.parse(newDate.substring(0, 4) + "-" + newDate.substring(4, 6) + "-" + newDate.substring(6, 8) + " " + newDate.substring(8, 10) + ":" + newDate.substring(10, 12) + ":" + newDate.substring(12, 14)));//业务实现,把订单信息保存到数据库//tblAutoOrderDatService.add(tblAutoOrderDat);}/*----------------------分割线,业务结束--------------------------*/map.put("return_code", "SUCCESS");map.put("return_msg", "OK");return WxPayUtil.getMapToXml(map);}/*** 根据微信订单号查询订单状态** @param transactionId 微信订单号* @return SUCCESS/FAIL*/@GetMapping("/getOrderStates/{transactionId}")public String getOrderStates(@PathVariable("transactionId") String transactionId) {Map<String, String> params = OrderQueryModel.builder().appid(wxPayProperties.getAppId()).mch_id(wxPayProperties.getMchId()).transaction_id(transactionId).nonce_str(WxPayKit.generateStr()).build().createSign(wxPayProperties.getMchKey(), SignType.MD5);String xml = WxPayApi.orderQuery(false, params);Map<String, String> resultMap = WxPayKit.xmlToMap(xml);log.info("resultMap:" + resultMap);return resultMap.get("result_code");}
}
还有一个在和APP前端对接的问题很坑。官方API的问题.导致后端的签名已经通过.APP拉不起支付。报支付签名验证失败。遇到此类的问题可参考下。
Over.