这篇教程将详细的介绍如何实现微信APP支付,分为Android移动端开发和springboot后端开发,有一些在开发过程中遇到的坑将会被标注,解决方案也会给出。

一、准备工作

准备工作就是获取必要的参数,注册微信商户平台和微信开放平台分别获取到商户号和APPID,并且在微信商户平台申请API证书、设置API密钥、设置APIv3密钥等



这些工作在公司里会有相关人员做好,将参数给出,直接拿来用即可。准备工作就是比较繁琐,而且微信开发者认证需要300元。做完相关工作后,一定要查看权限是否申请到,微信商户平台是否关联APPID等。由于这些东西全是我一个人做,所以对流程比较了解。

二、Springboot后端开发

先介绍一下微信支付的后端开发,微信APP支付开发与支付宝支付不一样,所以在这边需要将后端搭建好。打开微信支付的文档中心,我们主要根据官方给的提示按照步骤操作就可以了。这里我们就仅展示APP下单。

1、创建项目

主要的目录结构如下。包含了配置类,工具类等。包名 com.atguigu.paymentdemo(借鉴了网课)

2、配置文件application.yml和wxpay.properties

application.yml

server:port: 8090 #服务端口spring:application:name: payment-demo #应用的名字jackson:date-format: yyyy-MM-dd HH:mm:sstime-zone: GMT+8datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://ip:3310/payment_demo?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=falseusername: 用户名password: 密码mybatis-plus:configuration: #sql日志log-impl: org.apache.ibatis.logging.stdout.StdOutImplmapper-locations: classpath:com/atguigu/paymentdemo/mapper/xml/*.xmllogging:level:root: info

wxpay.properties

# 微信支付相关参数
# 商户号
wxpay.mch-id=商户号写自己的
# 商户API证书序列号
wxpay.mch-serial-no=写自己的# 商户私钥文件
wxpay.private-key-path=apiclient_key.pem
# APIv3密钥
wxpay.api-v3-key=写自己的
# API密钥
wxpay.api-key=写自己的
# APPID
wxpay.appid=写自己的
# 微信服务器地址
wxpay.domain=https://api.mch.weixin.qq.com
# 接收结果通知地址
wxpay.notify-domain=https://ip或者域名

注意:

  • 这里需要注意将上面的参数改为自己申请到的数据(商户号、序列号、秘钥等等),逐个修改就可以
  • 这里将申请到的商户私钥文件apiclient_key.pem放在了根目录下
  • 接受回调的通知地址wxpay.notify-domain这里需要注意一下,官方文档说必须为https地址,所以这里我们就使用一个内网穿透工具生成一个HTTPS地址。请自行查看ngrok这个工具。公司里应该都会给的。

3、配置文件pom.xml

pom.xml

<!--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><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--mysql 驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><!--MyBatis-Plus:是MyBatis的增强--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.1</version></dependency><!-- 代码生成器配置 --><dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifactId><version>2.0</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.4.1</version></dependency><!-- 生成自定义配置的元数据信息 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><!--微信支付SDK--><dependency><groupId>com.github.wechatpay-apiv3</groupId><artifactId>wechatpay-apache-httpclient</artifactId><version>0.3.0</version></dependency><!--json处理器--><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId></dependency><!--网络请求--><!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp --><dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.9.3</version></dependency>

由于项目打包时会将mapper目录下xml文件漏掉,所以我们在application.yml文件下配置了classpath:com/atguigu/paymentdemo/mapper/xml/.xml,同时在pom文件下的build下加入下面代码就可以了,这样就会在打包时将java目录中的.xml文件也进行打包。

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

为了让读者更好的复现这些功能,下面尽可能的将用到的代码都放在文章里。

4、vo包

这个目录主要是生成两个文件,使用swagger测试时查看响应码以及收到消息。

ResultCode

public interface ResultCode {public static Integer SUCCESS = 20000;//成功public static Integer ERROR = 20001;//失败
}

R

@Data
@Accessors(chain = true)
public class R {@ApiModelProperty(value = "是否成功")private Boolean success;@ApiModelProperty(value = "返回码")private Integer code;@ApiModelProperty(value = "返回消息")private String message;@ApiModelProperty(value = "返回数据")private Map<String, Object> data = new HashMap<String, Object>();//构造方法私有化private R(){}//链式编程//成功静态方法public static R ok(){R r = new R();r.setSuccess(true);r.setCode(ResultCode.SUCCESS);r.setMessage("成功");return r;}//失败静态方法public static R error(){R r = new R();r.setSuccess(false);r.setCode(ResultCode.ERROR);r.setMessage("失败");return r;}public R success(Boolean success){this.setSuccess(success);return this;}public R message(String message){this.setMessage(message);return this;}public R code(Integer code){this.setCode(code);return this;}public R data(String key, Object value){this.data.put(key, value);return this;}public R data(Map<String, Object> map){this.setData(map);return this;}
}

5、config包

这个目录主要是配置信息,配置Swagger、MyBatisPlus以及WxPay微信支付的参数

Swagger2Config

@Configuration
@EnableSwagger2
public class Swagger2Config {@Beanpublic Docket docket(){return new Docket(DocumentationType.SWAGGER_2).apiInfo(new ApiInfoBuilder().title("微信支付案例接口文档").build());}
}

MyBatisPlusConfig

@Configuration
@MapperScan("com.atguigu.paymentdemo.mapper")
@EnableTransactionManagement //启用事务管理
public class MyBatisPlusConfig {}

WxPayConfig

这个文件就是读取到wxpay.properties的信息

@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;// API密钥private String apiKey;// APPIDprivate String appid;// 微信服务器地址private String domain;// 接收结果通知地址private String notifyDomain;/*** 获取商户的私钥文件* @param filename* @return*/public PrivateKey getPrivateKey(String filename){try {return PemUtil.loadPrivateKey(new FileInputStream(filename));} catch (FileNotFoundException e) {throw new RuntimeException("私钥文件不存在", e);}}/*** 获取签名验证器* @return*/@Beanpublic 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;}/*** 获取HttpClient,无需进行应答签名验证,跳过验签的流程*/@Bean(name = "wxPayNoSignClient")public CloseableHttpClient getWxPayNoSignClient(){//获取商户私钥PrivateKey privateKey = getPrivateKey(privateKeyPath);//用于构造HttpClientWechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()//设置商户信息.withMerchant(mchId, mchSerialNo, privateKey)//无需进行签名验证、通过withValidator((response) -> true)实现.withValidator((response) -> true);// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新CloseableHttpClient httpClient = builder.build();log.info("== getWxPayNoSignClient END ==");return httpClient;}
}

6、enums包

这个主要是定义微信支付的提供的地址,将其设置为枚举型,进行拼接就可以组装成URL地址

WxApiType

@AllArgsConstructor
@Getter
public enum WxApiType {/*** APP下单*/APP_PAY("/v3/pay/transactions/app"),/*** 类型*/private final String type;
}

WxNotifyType

@AllArgsConstructor
@Getter
public enum WxNotifyType {/*** APP支付通知*/APP_NOTIFY("/api/wx-pay/app/notify"),/*** 类型*/private final String type;
}

OrderStatus

@AllArgsConstructor
@Getter
public enum OrderStatus {/*** 未支付*/NOTPAY("未支付"),/*** 支付成功*/SUCCESS("支付成功"),/*** 已关闭*/CLOSED("超时已关闭"),/*** 已取消*/CANCEL("用户已取消"),/*** 退款中*/REFUND_PROCESSING("退款中"),/*** 已退款*/REFUND_SUCCESS("已退款"),/*** 退款异常*/REFUND_ABNORMAL("退款异常");/*** 类型*/private final String type;
}

PayType

@AllArgsConstructor
@Getter
public enum PayType {/*** 微信*/WXPAY("微信"),/*** 支付宝*/ALIPAY("支付宝");/*** 类型*/private final String type;
}

7、util工具包

HttpClientUtils

/*** http请求客户端*/
public class HttpClientUtils {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 HttpClientUtils(String url, Map<String, String> param) {this.url = url;this.param = param;}public HttpClientUtils(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("?");isFirst = false;}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;}}

HttpUtils

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

OrderNoUtils

/*** 订单号工具类** @author qy* @since 1.0*/
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;}}

WechatPay2ValidatorForRequest

/*** @author xy-peng*/
public class WechatPay2ValidatorForRequest {protected static final Logger log = LoggerFactory.getLogger(WechatPay2ValidatorForRequest.class);/*** 应答超时时间,单位为分钟*/protected static final long RESPONSE_EXPIRED_MINUTES = 5;protected final Verifier verifier;protected final String requestId;protected final String body;public WechatPay2ValidatorForRequest(Verifier verifier, String requestId, String body) {this.verifier = verifier;this.requestId = requestId;this.body = body;}protected static IllegalArgumentException parameterError(String message, Object... args) {message = String.format(message, args);return new IllegalArgumentException("parameter error: " + message);}protected static IllegalArgumentException verifyFail(String message, Object... args) {message = String.format(message, args);return new IllegalArgumentException("signature verify fail: " + message);}public final boolean validate(HttpServletRequest request) throws IOException {try {//处理请求参数validateParameters(request);//构造验签名串String message = buildMessage(request);String serial = request.getHeader(WECHAT_PAY_SERIAL);String signature = request.getHeader(WECHAT_PAY_SIGNATURE);//验签if (!verifier.verify(serial, message.getBytes(StandardCharsets.UTF_8), signature)) {throw verifyFail("serial=[%s] message=[%s] sign=[%s], request-id=[%s]",serial, message, signature, requestId);}} catch (IllegalArgumentException e) {log.warn(e.getMessage());return false;}return true;}protected final void validateParameters(HttpServletRequest request) {// NOTE: ensure HEADER_WECHAT_PAY_TIMESTAMP at lastString[] headers = {WECHAT_PAY_SERIAL, WECHAT_PAY_SIGNATURE, WECHAT_PAY_NONCE, WECHAT_PAY_TIMESTAMP};String header = null;for (String headerName : headers) {header = request.getHeader(headerName);if (header == null) {throw parameterError("empty [%s], request-id=[%s]", headerName, requestId);}}//判断请求是否过期String timestampStr = header;try {Instant responseTime = Instant.ofEpochSecond(Long.parseLong(timestampStr));// 拒绝过期请求if (Duration.between(responseTime, Instant.now()).abs().toMinutes() >= RESPONSE_EXPIRED_MINUTES) {throw parameterError("timestamp=[%s] expires, request-id=[%s]", timestampStr, requestId);}} catch (DateTimeException | NumberFormatException e) {throw parameterError("invalid timestamp=[%s], request-id=[%s]", timestampStr, requestId);}}protected final String buildMessage(HttpServletRequest request) throws IOException {String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);String nonce = request.getHeader(WECHAT_PAY_NONCE);return timestamp + "\n"+ nonce + "\n"+ body + "\n";}protected final String getResponseBody(CloseableHttpResponse response) throws IOException {HttpEntity entity = response.getEntity();return (entity != null && entity.isRepeatable()) ? EntityUtils.toString(entity) : "";}}

这上面都是网课里的东西,我直接拿过来用的,都复制过来了。

8、controller包

上面的都是相关的配置文件,终于到重点部分了。在这里我省略了一些东西,Android端发起微信支付的时候,没有给参数,只展示了这个场景,每个人的需求不一样,如果需要参数,请自行改动接口,下面代码我给注释掉了。

WxPayController

@RestController
@RequestMapping("/api/wx-pay")
@Api(tags = "微信APP支付APIv3")
@Slf4j
public class WxPayController {@Resourceprivate WxPayService wxPayService;/*** APP下单* @param* @return* @throws Exception*/@ApiOperation("调用统一下单API,生成APP下单的预支付交易会话标识")
//    @PostMapping("/native/{productId}")@PostMapping("/native")
//    public R APPPay(@PathVariable Long productId) throws Exception {public R APPPay() throws Exception {log.info("发起支付请求 v3");//返回支付所需要的参数给Android端Map<String, Object> map = wxPayService.appPay();log.info("map====>{}",map);return R.ok().setData(map);}
}

9、service包

WxPayService

public interface WxPayService {/*** app下单* @param* @return*/Map<String, Object> appPay() throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException;
}

WxPayServiceImpl

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {@Resourceprivate WxPayConfig wxPayConfig;@Resourceprivate CloseableHttpClient wxPayClient;protected static final SecureRandom RANDOM = new SecureRandom();/*** APP下单* @param* @return*/@Overridepublic Map<String, Object> appPay() throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {log.info("生成订单");String orderNo = OrderNoUtils.getOrderNo();//生成订单log.info("调用统一下单API");//调用统一下单APIHttpPost httpPost = new HttpPost(wxPayConfig.getDomain().concat(WxApiType.APP_PAY.getType()));// 请求body参数Gson gson = new Gson();Map paramsMap = new HashMap();paramsMap.put("appid", wxPayConfig.getAppid());paramsMap.put("mchid", wxPayConfig.getMchId());paramsMap.put("description", "whq烤肉");paramsMap.put("out_trade_no", orderNo);paramsMap.put("notify_url", wxPayConfig.getNotifyDomain().concat(WxNotifyType.APP_NOTIFY.getType()));Map amountMap = new HashMap();amountMap.put("total", 1);amountMap.put("currency", "CNY");paramsMap.put("amount", amountMap);//将参数转换成json字符串String jsonParams = gson.toJson(paramsMap);log.info("请求参数 ===> {}" + jsonParams);StringEntity entity = new StringEntity(jsonParams,"utf-8");entity.setContentType("application/json");httpPost.setEntity(entity);httpPost.setHeader("Accept", "application/json");//完成签名并执行请求CloseableHttpResponse response = wxPayClient.execute(httpPost);try {String bodyAsString = EntityUtils.toString(response.getEntity());//响应体int statusCode = response.getStatusLine().getStatusCode();//响应状态码if (statusCode == 200) { //处理成功log.info("成功, 返回结果 = " + bodyAsString);} else if (statusCode == 204) { //处理成功,无返回Bodylog.info("成功");} else {log.info("APP下单失败,响应码 = " + statusCode+ ",返回结果 = " + bodyAsString);throw new IOException("request failed");}//响应结果Map<String, String> resultMap = gson.fromJson(bodyAsString, HashMap.class);//得到返回参数String prepay_id = resultMap.get("prepay_id");Map gettoken = getToken(wxPayConfig.getAppid(),prepay_id);String nonceStr = (String) gettoken.get("nonceStr");String sign = (String) gettoken.get("signature");long timestamp = (long) gettoken.get("timestamp");//返回得到的返回参数Map<String, Object> map = new HashMap<>();map.put("prepayid", prepay_id);map.put("sign", sign);map.put("appid", wxPayConfig.getAppid());map.put("partnerid", wxPayConfig.getMchId());map.put("packagevalue", "Sign=WXPay");map.put("noncestr", nonceStr);map.put("timestamp", timestamp);return map;} finally {response.close();}}/*** 生成字符串* @return*/protected String generateNonceStr() {char[] nonceChars = new char[32];for(int index = 0; index < nonceChars.length; ++index) {nonceChars[index] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".charAt(RANDOM.nextInt("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".length()));}return new String(nonceChars);}/*** 生成签名值* @param appid* @param prepay_id* @return* @throws IOException* @throws SignatureException* @throws NoSuchAlgorithmException* @throws InvalidKeyException*/Map<String,Object> getToken(String appid,String prepay_id) throws IOException, SignatureException, NoSuchAlgorithmException, InvalidKeyException {//随机字符串String nonceStr = this.generateNonceStr();//随机字符串//时间戳long timestamp = System.currentTimeMillis() / 1000;//从下往上依次生成String message = buildMessage(appid, timestamp, nonceStr, prepay_id);//签名String signature = sign(message.getBytes("utf-8"));Map<String , Object> map = new HashMap<>();map.put("timestamp",timestamp);map.put("nonceStr",nonceStr);map.put("signature",signature);return map;}String sign(byte[] message) throws NoSuchAlgorithmException, SignatureException, IOException, InvalidKeyException {//签名方式Signature sign = Signature.getInstance("SHA256withRSA");//私钥,通过MyPrivateKey来获取,这是个静态类可以接调用方法 ,需要的是_key.pem文件的绝对路径配上文件名//获取商户私钥PrivateKey privateKey = wxPayConfig.getPrivateKey(wxPayConfig.getPrivateKeyPath());sign.initSign(privateKey);sign.update(message);return Base64.getEncoder().encodeToString(sign.sign());}/***  按照前端签名文档规范进行排序,\n是换行* @param appid* @param timestamp* @param nonceStr* @param prepay_id* @return*/String buildMessage(String appid, long timestamp,String nonceStr,String prepay_id) {return appid + "\n"+ timestamp + "\n"+ nonceStr + "\n"+ prepay_id + "\n";}
}

到这里后端的项目就算完成了,此时运行起来就行了。打开swagger进行测试

返回参数就是这些。我们Android进行接收就完成了!
注意:
以上只是简单的给出微信APP下单的实现,公司里的需要要更完善,比如保存订单和订单状态,产品等等,这些都要与数据库交互,所以在上面基础上继续完成功能就可以了。

微信APP支付-Android+springboot搭建后端(一)相关推荐

  1. 实现微信app支付的springboot项目

    1.1请先完成微信APP支付接入商户服务中心 1.2详情请参考微信官方文档:https://open.weixin.qq.com/ 2.application.yml文件的配置如下 #微信支付配置 t ...

  2. android 支付系统 demo,微信APP支付Android Demo详解

    根据这篇文章的步骤,可以让你的账号跑通android app的微信支付. 前提:已经有开通微信支付,有商户号,密钥. 点击图片可以打开大图查看. 1. 下载Android app Demo 2. 安装 ...

  3. Android安卓原生接入微信app支付PHP服务端

    Android安卓接入微信app支付PHP服务端 1.进入微信商户平台查看统一下单接口文档. 在查看完统一下单文档后,能够看到需要传递给微信"统一下单接口"地址的参数有哪些 统一下 ...

  4. android微信支付都需要什么意思,Android开发微信APP支付功能的要点小结

    基本概念 包名值得是你APP的包,在创建工程时候设置的,需要在微信支付平台上面设置. 签名指的是你生成APK时候所用的签名文件的md5,去掉:全部小写,需要在微信支付平台上面设置. 调试阶段,签名文件 ...

  5. Android版-微信APP支付

    首发地址: Android版-微信APP支付 欢迎留言.转发 微信极速开发系列文章(微信支付.授权获取用户信息等):点击这里 目录 1.注册账号.开发者认证 2.添加应用 3.申请微信支付 4.技术开 ...

  6. 微信app支付 java后台接Android

    抽时间整理一下之前项目中的微信app支付,以备以后需要,如果对你可以有点帮助是最好不过的: 直接上代码: public class WeChatAppConfig {/*** 预支付请求地址*/pub ...

  7. java后端+uniapp 对接微信app支付 报错-1

    问题描述: 原因分析: 上面两张图片完美的呈现了对接微信APP支付所能遇见的问题 排查流程: 检测自己的app是否 以及注册到微信开放平台 并且填写了与APP中的包名相对应的 检测自己的App是否开通 ...

  8. 微信APP支付填坑记

    首先吐槽几句,微信支付很强大,古人有诗赞曰:自古多坑空余恨,此坑绵绵无绝期. 先说几个必做前置任务: 1 在微信商户平台设置你的公用key,程序里生成sign签名时,要用到这个key.为md5 32位 ...

  9. 微信App支付全解析

    简单介绍了微信移动支付的申请.接入.使用.确认支付结果等相关流程 0 系列文章 系列一 微信App支付全解析 系列二 支付宝App支付全解析 系列三 微信公众号支付全解析 系列四 微信扫码支付全解析 ...

  10. 微信app支付功能-服务端的实现-python3版

    微信app支付功能-服务端的实现-python3版 一:需求说明 二:微信app支付处理流程 三:所需依赖 3.1 支付配置 四:接口开发 4.1 创建订单接口 4.2 微信异步回调接口 4.3 订单 ...

最新文章

  1. 图解Istio原理和实践--云平台技术栈18
  2. 正则表达式 字符转义
  3. python done()什么意思_Python done
  4. linux下lua开发环境安装
  5. ElasticSearch6.x 7.x Elasticdump 在线安装、离线安装
  6. 忘记MySQL密码怎么办?一招教你搞定!
  7. C#删除字符串最后一个字符的几种方法
  8. 计算机通过逻辑电路实现运算,计算机组成与体系结构数据表示与运算算法和逻辑电路实现.ppt...
  9. PHP程序员测试题及答案
  10. AR公共安全及应急指挥中的应用 | TVP思享
  11. ubuntu linux 教程 pdf,Ubuntu 12.04 菜鸟完全使用教程(二) PDF
  12. numpy下载失败解决方法
  13. 指数波段划分以及底部反弹行业特征统计分析
  14. 「模拟8.19 A嚎叫..(set) B主仆..(DFS) C征程..(DP+堆优化)」
  15. 从输入URL到页面加载…
  16. Google Nexus 5 root后显示文件系统/system只读
  17. Hive基础知识及底层架构
  18. MySQL大厂优化方案轻松应对高并发!真牛!
  19. Unity编写冰球对战游戏 2D版
  20. DeepFM原理及tensorflow代码实战

热门文章

  1. 如何使用计算机小学生课件,小学信息技术计算机基础ppt课件
  2. matlab逆滤波、维纳滤波、最小二乘滤波
  3. 全国2009年1月电子商务与电子政务试题
  4. VMware Workstation Pro v16.1.0虚拟机下载安装过程
  5. armv6 armv7 armv7s架构的区别
  6. 【数智化案例展】深农集团——守护深圳“菜篮子”,腾讯安全携手深农集团保供稳价格...
  7. SQL Server中查询ORACLE的数据
  8. linux 锐捷 自动,Linux 锐捷自动交互认证
  9. 从头开始vue创建项目_从头开始创建Windows 7主题包
  10. CocosBuilder