微信免资金代金券(V3版)java代码
开始之前先让博主吐槽下微信的接口文档与接口规则。一个代金券的模块搞了3个星期。严重怀疑微信的产品经理跟项目经理有病。写文档的程序员也是。吐槽结束。
一、准备
- 微信公众号的AppId和密钥Secret
- v3接口的证书号和证书(.pem文件)
- v3Api密钥(用于解析核销通知)
- 耐心和刀!!(可以随时捅死微信的程序员)
ps:如果是商户自己调用api的话(这一步不做的话会报
body={"code":"INVALID_REQUEST","message":"可用商户不符合规则,请检查"})
需要去商家支付平台开启产品--》https://pay.weixin.qq.com/ 在产品中心下--》我的产品--》开通免资金代金券
如果是服务商调用需要进入邀请商户授权,当服务商点击发起授权后,需要商户进入商户平台确认邀请(商户的支付平台在上面消息中心确定授权,不授权的话服务商无法帮商户创建代金券)当商户授权完,商户账号下也需要开启免资金代金券的功能。
二、第三方框架导入
在这里感谢 Javen大佬的 IJPay-WxPay框架
Github地址: https://github.com/Javen205/IJPay
Gitee:http://gitee.com/Javen205/IJPay
<dependency><groupId>com.github.javen205</groupId><artifactId>IJPay-WxPay</artifactId><version>2.6.3</version> </dependency>
本人使用的时候该版本的v3接口还不算太完善,所以我只是使用了这个框架的调用微信v3的请求方法
新的应该已经支持直接调用代金券接口创建了吧。
其他使用到的关键
<!-- 阿里json --> <dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.62</version> </dependency>
lombok <!-- lombok --> <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional> </dependency>
// 这两个框架可以不加(本人用于测试接口用的,相关配置可以参考对应的文档) <!-- swagger2 --> <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version> </dependency> <!-- swagger-ui --> <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.9.2</version> </dependency>
三、上代码
微信的配置文件
import lombok.Data;/*** @Description: 微信配置* @Author: Joshua* @CreateDate: 2020/7/16 12:39* @Version 1.0*/
@Data
public class WxConfig {public static WxConfig wxConfig;/*** 服务商appid*/// 服务号public final static String APPID = "你的AppId";/*** secret*/public final static String SECRET = "你的密钥";/*** v3私钥*/public final static String PRIVATE_KEY = "你的私钥";/*** v3* 证书号(会过期) 40个字符*/public final static String SERIAL_NO = "证书号";/*** 证书路径(我直接放在项目路径下)*/public final static String KEY_PATH = "../../apiclient_key.pem";/*** v3* API密钥(自己设置的32字符)*/public final static String API_V3_KEY = "v3API密钥";/*** 服务商商户号(如果你是服务商,如果是商户着就是商户号)*/public final static String MCH_ID = "服务商商户号";/*** 微信代金券通知地址(必须是https的)*/public final static String COUPON_NOTIFY = "https://...../redirect-anon/wxCouponNotify";}
请求实体(里面有些字段是我自己需要使用的,其他开发者看着需求更改)
import java.io.Serializable;
import java.util.Date;import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import javax.persistence.*;/*** 微信优惠券** @author Joshua* @since 2020-08-01*/
@Data
@Entity
@Table(name = "wx_coupon")
@ApiModel(value = "WxCoupon", description = " 微信优惠券")
public class WxCoupon implements Serializable {private static final long serialVersionUID = 1L;/*** 主鍵Id*/@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@ApiModelProperty(name = "id", value = "id", example = "1")private Integer id;/*** 商户id*/@ApiModelProperty(name = "merchantId", value = "商户id")private Integer merchantId;/*** 子商户号*/@ApiModelProperty(name = "belongMerchant", value = "子商户号")private String belongMerchant;/*** 卡券标题*/@ApiModelProperty(name = "stockName", value = "卡券标题")private String stockName;/*** 开始时间*/@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")@ApiModelProperty(name = "beginTimestamp", value = "开始时间")private Date beginTimestamp;/*** 结束时间*/@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")@ApiModelProperty(name = "endTimestamp", value = "结束时间")private Date endTimestamp;/*** 发行量*/@ApiModelProperty(name = "maxCoupons", value = "发行量")private Integer maxCoupons;/*** 面额(单位:分)*/@Transient@ApiModelProperty(name = "couponAmount", value = "面额(单位:分)")private Integer couponAmount;/*** 门槛(单位:分)*/@Transient@ApiModelProperty(name = "transactionMinimum", value = "门槛(单位:分)")private Integer transactionMinimum;/*** 核销规则*/private String rule;/*** 单个用户可领个数,每个用户最多60张券*/@Transient@ApiModelProperty(name = "maxCouponsPerUser", value = "单个用户可领个数, 0< maxCouponsPerUser <=60")private Integer maxCouponsPerUser;/*** 是否开启自然人限制(默认:false)* 如果开启,则1个自然人有多个微信号,会视为同一个人。* 开启后当一个自然人用户某个微信好享受优惠,使用其他微信号时将无法享受优惠* PS:可能会造成用户投诉*/@Transient@ApiModelProperty(name = "naturalPersonLimit", value = "是否开启自然人限制(默认:false)")private Boolean naturalPersonLimit;/*** api发券防刷(默认:false)*/@Transient@ApiModelProperty(name = "preventApiAbuse", value = "api发券防刷(默认:false)")private Boolean preventApiAbuse;/*** 商家logo*/@Transient@ApiModelProperty(name = "logo", value = "商家logo")private String logo;/*** 可用时间段(0为周日,1为周一以此类推)格式[0,1,2,3,4,5,6]*/@Transient@ApiModelProperty(name = "availableWeekDay", value = "可用时间段")private String availableWeekDay;/*** 卡券类型(0满减券,1折扣券)*/@ApiModelProperty(name = "cardType", value = "卡券类型(0满减券,1折扣券)")private Integer cardType;/*** 最高折扣金额(单位分)*/@Transient@ApiModelProperty(name = "discountAmountMax", value = "最高折扣金额")private Integer discountAmountMax;/*** 折扣百分比*/@Transient@ApiModelProperty(name = "discountPercent", value = "折扣百分比(70=7折)")private Integer discountPercent;/*** 創建時間*/@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")@ApiModelProperty(name = "createTime", value = "創建時間")private Date createTime;/*** 卡券id*/@ApiModelProperty(name = "stockId", value = "卡券id")private String stockId;/*** 卡券状态*/@ApiModelProperty(name = "status", value = "卡券状态(0:已失效,未失效)")private Integer status;/*** 商户名称*/@Transient@ApiModelProperty(name = "merchantName", value = "商户名称")private String merchantName;
}
Controller层(关于ResponseObj这个实体,只是一个普通的三段式相应参数)
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.Date;
import java.util.Map;/*** @Description: 微信卡券* @Author: Joshua* @CreateDate: 2020/7/31 11:55* @Version 1.0*/
@Slf4j
@RestController
@RequestMapping("/wxCouponController")
@Api(value = "微信卡券", tags = {"微信卡券"})
public class WxCouponController {// 因为使用分布式(所以有些数据需要远程调用拿,如果是本地开发不需要这个)@AutowiredMerchant merchant;// 这两个是存表的实现类,里面只有insert方法(看自己需求更改)@AutowiredWxCouponService wxCouponService;@AutowiredWxCouponUserService wxCouponUserService;/*** 设置回调地址** @return 200*/@ApiOperation("设置回调地址")@GetMapping("/sendCallbacks")public ResponseObj sendCallbacks() {try {Map<String, Object> sendCallbacks = WxUtils.sendCallbacks(WxConfig.MCH_ID);System.out.println(sendCallbacks.toString());JSONObject body = JSONObject.parseObject(sendCallbacks.get("body").toString());if (200 == (Integer) sendCallbacks.get("status")) {System.out.println(body);} else {// 请求异常是打印错误到前台return ResponseObj.createResponse(666, body.get("message").toString());}} catch (Exception e) {e.printStackTrace();}return ResponseObj.createSuccessResponse();}/*** 创建优惠券** @param coupon 创建实体* @return 200*/@ApiOperation("创建优惠券")@PostMapping("/createCoupon")public ResponseObj createCoupon(@RequestBody WxCoupon coupon) {// 因为我是远端调用的方法(一般开放者可以忽略这步)ResponseData wxMchIdByMchId = merchant.getMchNameAndWxMchIdByMchId(Long.valueOf(coupon.getMerchantId()));Map<String, String> data = (Map<String, String>) wxMchIdByMchId.getData();// 服务商调用时需要用到子商户id,如果普通商户调用不需要。coupon.setBelongMerchant(data.get("wxMchId"));// 获取商家名称(可有可无)coupon.setMerchantName(data.get("merchantName"));// 构建请求JsonString createCoupon = ProcessCardData.createCoupon(coupon);System.out.println(createCoupon);try {Map<String, Object> v3Coupon = WxUtils.createV3Coupon(createCoupon);JSONObject body = JSONObject.parseObject(v3Coupon.get("body").toString());System.out.println("创建优惠券:" + body);if (200 == (Integer) v3Coupon.get("status")) {String stockId = String.valueOf(body.get("stock_id"));// 激活代金券Map<String, Object> activationCoupon = WxUtils.activationCoupon(stockId);if (200 == (Integer) activationCoupon.get("status")) {System.out.println("激活代金券:" + activationCoupon.get("body"));coupon.setStatus(1);} else {System.out.println("激活代金券:" + activationCoupon.get("body"));coupon.setStatus(0);}coupon.setCreateTime(new Date());coupon.setStockId(stockId);coupon.setRule(ProcessData.processRule(coupon.getTransactionMinimum(), coupon.getCouponAmount()));wxCouponService.insert(coupon);} else {return ResponseObj.createResponse(666, body.get("message").toString());}} catch (Exception e) {e.printStackTrace();log.error(e.getMessage());}return ResponseObj.createSuccessResponse();}/*** 激活代金券* 防止创建时调用激活接口失败,可重新调用激活* @param id 主键id* @param stockId 卡券id* @return 200*/@ApiOperation("激活代金券")@ApiImplicitParams({@ApiImplicitParam(name = "id", value = "主键id", paramType = "query", dataType = "Integer"),@ApiImplicitParam(name = "stockId", value = "卡券id", paramType = "query", dataType = "Integer")})@GetMapping("/activationCoupon")public ResponseObj activationCoupon(@RequestParam Integer id, @RequestParam String stockId) {try {Map<String, Object> activationCoupon = WxUtils.activationCoupon(stockId);if (200 == (Integer) activationCoupon.get("status")) {System.out.println("激活代金券:" + JSONObject.parseObject(activationCoupon.get("body").toString()));WxCoupon coupon = new WxCoupon();coupon.setId(id);coupon.setStatus(1);wxCouponService.update(coupon);} else {return ResponseObj.createErrResponse(JSONObject.parseObject(activationCoupon.get("body").toString()).get("message").toString());}} catch (Exception e) {e.printStackTrace();}return ResponseObj.createSuccessResponse();}/*** 投放代金券** @param couponUser 实体* @return 200*/@ApiOperation("投放代金券")@PostMapping("/sendCoupon")public ResponseObj sendCoupon(@RequestBody WxCouponUser couponUser) {try {Map<String, Object> sendCoupon = WxUtils.sendCoupon(couponUser.getBelongMerchant(), couponUser.getStockId(), couponUser.getOpenid());JSONObject body = JSONObject.parseObject(sendCoupon.get("body").toString());System.out.println("投放代金券:" + body);if (200 == (Integer) sendCoupon.get("status")) {couponUser.setCouponId(String.valueOf(body.get("coupon_id")));couponUser.setCreateTime(new Date());wxCouponUserService.insert(couponUser);} else {return ResponseObj.createResponse(666, body.get("message").toString());}} catch (Exception e) {e.printStackTrace();}return ResponseObj.createSuccessResponse();}}
构建创建卡券的请求json字符串(body)
/*** 创建代金券** @param coupon 创建实体* @return createCoupon*/public static String createCoupon(WxCoupon coupon) {String createCoupon;// 卡券类型String couponType;if (0 == coupon.getCardType()) {// 面额和门槛(单位都是分)couponType = "\"fixed_normal_coupon\":{\"coupon_amount\":" + coupon.getCouponAmount() + ",\"transaction_minimum\":" + coupon.getTransactionMinimum() + "},";} else if (1 == coupon.getCardType()) {// 折扣券(单位都是分)couponType = "\"disscount_coupon\":{\"discount_amount_max\":" + coupon.getDiscountAmountMax() + ",\"discount_percent\":" + coupon.getDiscountPercent() + ",\"transaction_minimum\":" + coupon.getTransactionMinimum() + "},";} else {couponType = "";}String merchantLogo = "";if (null != coupon.getLogo()) {merchantLogo = "\"merchant_logo\":\"" + coupon.getLogo() + "\",";}// 这个值可以随意创建,只要保证唯一即可(不用在意我的创建方法)// 商户创建批次凭据号(格式:商户id+日期+流水号),可包含英文字母,数字,|,_,*,-等内容,不允许出现其他不合法符号,商户侧需保持唯一性 (9856886520200811174644kk6tclE)String outRequestNo = coupon.getBelongMerchant() + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + CommonUtil.getRandomString2(7);createCoupon = "{"+ "\"stock_name\":\"" + coupon.getStockName() + "\","// 商户号(1600907583)
// + "\"belong_merchant\":\"" + coupon.getBelongMerchant() + "\","+ "\"belong_merchant\":\"" + WxConfig.MCH_ID + "\","// 开始与结束时间(2015-05-20T13:29:35.120+08:00)+ "\"available_begin_time\":\"" + DateUtil.getRfc3339(coupon.getBeginTimestamp()) + "\",\"available_end_time\":\"" + DateUtil.getRfc3339(coupon.getEndTimestamp()) + "\","+ "\"stock_use_rule\":{"// 发行量+ "\"max_coupons\":" + coupon.getMaxCoupons() + ","// 总预算[单位:分 coupon_amount(面额) * max_coupons(发放总上限)]+ "\"max_amount\":" + (coupon.getCouponAmount() * coupon.getMaxCoupons()) + ","// 限制当天的发放上限金额(单位:分)+ "\"max_amount_by_day\":" + (coupon.getCouponAmount() * coupon.getMaxCoupons()) + ","// 单个用户可领取的上限+ "\"max_coupons_per_user\":" + coupon.getMaxCouponsPerUser() + ","// 是否开启自然人限制+ "\"natural_person_limit\":" + coupon.getNaturalPersonLimit() + ","// 是否开启Api防刷+ "\"prevent_api_abuse\":" + coupon.getPreventApiAbuse() + "},"// stock_use_rule 结束+ "\"pattern_info\":{"// 使用说明+ "\"description\":\"代金券\","// 商家图标(可空)+ merchantLogo// 卡券商家名称+ "\"merchant_name\":\"" + coupon.getMerchantName() + "\""
// + ",\"background_color\":\"Color010\""+ "},"// pattern_info 结束+ "\"coupon_use_rule\":{"// TODO 如果开启下面的在激活的时候会报“卡包信息尚未注册完成,请稍后重试” ,具体问题未知。// 券生效时间
// + "\"coupon_available_time\":{"
// // 固定时间段
// + "\"fix_available_time\":{"
// // 可用时间段(0为周日,1为周一)
// + "\"available_week_day\":" + coupon.getAvailableWeekDay() + ","
// // 当天开始与结束时间
// + "\"begin_time\":0,\"end_time\":3600},"
// // fix_available_time 结束
// // 领取第二天生效
// + "\"second_day_available\":false"
// // 领取后有效时间+ ",\"available_time_after_receive\":1440"
// + "},"// coupon_available_time 结束// 卡券类型+ couponType// 支付方式 (微信的官方文档是错误的,这里应传数组)+ "\"trade_type\":[\"MICROAPP\",\"APPPAY\",\"PPAY\",\"CARD\",\"FACE\",\"OTHER\"],"// 是否可叠加其他优惠+ "\"combine_use\":false,"// 可核销商户号(多个商户共同核销时可传入多个商户号["子商户号A","子商户号B"])+ " \"available_merchants\":[\"" + coupon.getBelongMerchant() + "\"]"+ "},"// coupon_use_rule 结束// 是否无资金流+ "\"no_cash\":true,"// 卡券类型+ "\"stock_type\":\"NORMAL\","// 自定义单据号+ "\"out_request_no\":\"" + outRequestNo + "\""+ "}";return createCoupon;}
该createCoupon方法会使用到工具方法(其他的方法基本都是jdk自带的,不会涉及导包的)
/*** 转换rfc3339格式时间** @param date 时间* @return rfc3339Date*/public static String getRfc3339(Date date) {DateTime rfc3339Date = new DateTime(date, DateTimeZone.forTimeZone(TimeZone.getTimeZone("Asia/Shanghai")));return rfc3339Date.toString();}/*** 生成随机字符串** @param length* @return*/public static String getRandomString2(int length) {Random random = new Random();StringBuilder sb = new StringBuilder();for (int i = 0; i < length; ++i) {int number = random.nextInt(3);long ResponseObj = 0;switch (number) {case 0:ResponseObj = Math.round(Math.random() * 25 + 65);sb.append((char) ResponseObj);break;case 1:ResponseObj = Math.round(Math.random() * 25 + 97);sb.append((char) ResponseObj);break;case 2:sb.append(new Random().nextInt(10));break;default:}}return sb.toString();}
请求微信的方法
import com.ijpay.wxpay.WxPayApi;
import lombok.extern.slf4j.Slf4j;import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;import static com.ijpay.core.enums.RequestMethod.*;
import static com.ijpay.wxpay.enums.WxApiType.*;
import static com.ijpay.wxpay.enums.WxDomain.*;/*** @Description: 微信相关工具类* @Author: Joshua* @CreateDate: 2020/8/10 18:58* @Version 1.0*/
@Slf4j
public class WxUtils {/*** 创建代金券** @param requestJson 请求参数* @return map*/public static Map<String, Object> createV3Coupon(String requestJson) throws Exception {return WxPayApi.v3Execution(POST, CHINA.toString(), CREATE_COUPON_STOCKS.toString(), WxConfig.MCH_ID, WxConfig.SERIAL_NO, WxConfig.KEY_PATH, requestJson);}/*** 激活代金券** @param stockId 卡券批号* @return map* @throws Exception 异常*/public static Map<String, Object> activationCoupon(String stockId) throws Exception {String requestJson = "{\"stock_creator_mchid\":\"" + WxConfig.MCH_ID + "\"}";String urlSuffix = "/v3/marketing/favor/stocks/" + stockId + "/start";return WxPayApi.v3Execution(POST, CHINA.toString(), urlSuffix, WxConfig.MCH_ID, WxConfig.SERIAL_NO, WxConfig.KEY_PATH, requestJson);}/*** 放代金券** @param belongMerchant 商户号* @param stockId 卡券批号* @param openid 用户id* @return map* @throws Exception 异常*/public static Map<String, Object> sendCoupon(String belongMerchant, String stockId, String openid) throws Exception {String outRequestNo = belongMerchant + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + CommonUtil.getRandomString2(7);String requestJson = "{"+ "\"stock_id\": \"" + stockId + "\","+ "\"out_request_no\": \"" + outRequestNo + "\","+ "\"appid\": \"" + WxConfig.APPID + "\","+ "\"stock_creator_mchid\": \"" + WxConfig.MCH_ID + "\""+ "}";String urlSuffix = "/v3/marketing/favor/users/" + openid + "/coupons";return WxPayApi.v3Execution(POST, CHINA.toString(), urlSuffix, WxConfig.MCH_ID, WxConfig.SERIAL_NO, WxConfig.KEY_PATH, requestJson);}/*** 设置代金券回调地址** @param wxMchId 商户号* @return 200* @throws Exception 异常*/public static Map<String, Object> sendCallbacks(String wxMchId) throws Exception {String requestJson = "{"+ "\"mchid\": \"" + wxMchId + "\","+ "\"notify_url\": \"" + WxConfig.COUPON_NOTIFY + "\","+ "\"switch\":true"+ "}";return WxPayApi.v3Execution(POST, CHINA.toString(), SETTING_COUPON_CALLBACKS.toString(), WxConfig.MCH_ID, WxConfig.SERIAL_NO, WxConfig.KEY_PATH, requestJson);}
}
这样就可以创建代金券,激活代金券,发放代金券了
因为本人使用swagger做请求测试,下面是请求实例
创建代金券
{"merchantId": 22,//这个可以忽略"stockName": "测试券", //卡券名称"beginTimestamp": "2020-08-17 17:52:48", //开始时间"endTimestamp": "2020-08-18 23:59:59", //结束时间"maxCoupons": 10, //发放数量"maxCouponsPerUser": 1, //每个用户可以领取几次"naturalPersonLimit": false, //自然人限制(我一般不开,因为会影响用户的使用)"preventApiAbuse": false, //api防刷(同上)"cardType": 0, //卡券类型(可以忽略)"couponAmount": 100,(面额,单位:分 )"transactionMinimum": 101(门槛,单位:分 )
}
//这里有两个地方要注意:发放数量必须大于5,门槛必须比面额高,面额和门槛都需大于1元投放代金券
{"merchantId": 22, //这个可以忽略"belongMerchant": "子商户号", //如果是服务商调用需要子商户号,普通商户调用填写自己的商户号"openid": "app下对应的用户openId","stockId": "模板id"
}
关于卡券核销通知:
开启通知功能(如果是服务商自己使用,只需要服务商开启通知即可,如果服务商要为商户的公众号创建,这商户也需要开启此功能)(普通商户也需要开启此功能才能接收到卡券消息)
https://pay.weixin.qq.com/index.php/xphp/cmkt_product/index#/pages/index/index
开发流程就此结束,再次吐槽微信的接口与文档真垃圾
微信免资金代金券(V3版)java代码相关推荐
- 微信免充值代金券与免充值立减券与单品券活动验收流程
功能介绍 为支持商户免充值营销经费开展运营活动,提升运营效率,微信支付特开发免充值营销产品功能.商户开通该产品功能后,可免费使用微信支付提供的免充值代金券.立减.折扣等营销工具.商户配置使用免充值代金 ...
- 微信服务商开通免充值代金券接口升级验收
微信服务号开通免充值代金券接口升级验收 一.获取沙箱验签秘钥API 准备参数: 1.服务商商户号:mch_id 2.32位随机字符串:nonce_str 3.微信支付商户32位秘钥:key(获取签名s ...
- 微信支付--代金券免充值代金券:接口升级
微信支付–代金券免充值代金券 开通免充值代金券需 进行接口升级: https://pay.weixin.qq.com/wiki/doc/api/download/mczyscsyl.pdf 接口升级组 ...
- 微信支付免充值代金券接口升级免费开通步骤
无论是微信支付服务商还是普通商户,在创建代金券或立减折扣时,都希望能够实现免充值,在交易发生时直接抵扣,毕竟充值过程太啰嗦. 但是在微信支付商户平台上开通免充值相关产品(包括微信支付免充值代金券和微信 ...
- php微信支付商户免充值代金券接口升级
//todo 如果没安装该插件可删除该行,并使用参数requestType改为'1' use GuzzleHttp\Client;/*** Class Demo* @package ShopEM\Se ...
- 视频教程-微信生活缴费商业项目标准版-Java
微信生活缴费商业项目标准版 19年软件开发经验,设计开发40多个大型软件,10年从事高等教育,主要为java系列课程,带你轻松进入java生涯. 赖国荣 ¥399.00 立即订阅 扫码下载「CSDN程 ...
- 关于微信卡券与代金券的一些事
最近公司有个项目需要在H5上面发放代金券,研究了好几天微信公众平台和商户平台的文档,梳理下微信卡券和代金券之间的联系.以下微信公众平台简称mp平台,商户平台简称pay平台. mp平台开发文档 pay平 ...
- 剑指Offer第二版Java代码实现
剑指Offer第二版Java代码实现 A.单例模式 面试题 2:实现Singleton模式 B.面试需要的基础知识 面试题 3:数组中重复的数字 面试题 4:二维数组的查找 面试题 5:替换空格 面试 ...
- 微信支付V3版 java
微信支付V3版 1.引入依赖 2.创建时间工具类 DateTimeZoneUtil.class 3.解密工具类 AesUtil.class 4.对外暴露方法 公共参数 4-1.支付下单 V3PayGe ...
最新文章
- 如何在一个程序集中序列化在另一个中反序列化
- 远望资本田鸿飞:中国产业互联网的关键是AI赋能
- 【Linux网络编程】IP地址分类和介绍
- 面试指南|GO高性能编程精华PDF
- ftp获取远程Pdf文件
- 新浪微博推出具有中国特色的“关注但屏蔽”功能
- 递归算法(python),汉诺塔问题,斐波那契数列,一个简单的递归实例,用递归实现阶乘,用递归查看目录及文件
- PS零基础自学笔记:常见操作方法记录(去水印、抠图、调色调)
- 微信支付对账单的详细说明
- 如何xp计算机每天定时关机,xp定时关机,教您xp系统怎么设置定时关机
- 管理者如何抓绩效管理?
- 交换游戏(记忆化搜索,状态压缩,位运算)
- 【java毕业设计】基于javaEE+SSM+MySql的个人博客系统设计与实现(毕业论文+程序源码)——个人博客系统
- 高德地图看各省分界线_从高德采集最新的省市区三级坐标和行政区域边界,用js在浏览器中运行...
- 论天龙八部和程序员的关系
- php查询google pr值接口api介绍,最新 google pr值查询 接口 php版 示例
- 绝对零度!冷原子量子计算机技术的6大优势
- DJ音乐培训展示类网站织梦模板
- 如何学习新概念英语第四册
- EggDrop Problem(扔鸡蛋问题)