微信公众号开发流程
1、订阅号:主要偏于为用户传达资讯(类似报纸杂志),认证前后都是每天只可以群发一条消息;
2、服务号:主要偏于服务交互(类似银行,114,提供服务查询),认证前后都是每个月可群发4条消息
3)如果想用来管理内部企业员工、团队,对内使用,可申请企业号;
A:在微信·公众平台的官网上申请
不同类型由不同的权限,可在开发文档中查看具体有那些权限( 列举两个权限的对比)
B: 我们的服务器需要与微信服务器进行交互将本地的IP暴露到公网中供外部访问
自己测试可以使用一些内网穿透的工具
C:登录公众平台官网 基本配置
URL 这里外网IP是服务器的外网IP地址 端口号,配置好后点击提交微信服务器会向我们所填写的那个URL发起一个GET请求,并携带以下几个参数: 80
timestamp:时间戳, nonce 随机数, echostr 随机字符串, signature
主要时这个签名 前三个参数以及我们配置的token生产签名
开发者获得加密后的字符串可与signature对比,(通过生成方式 hashcode 进行对比)
验证签名成功后原样返回 echostr 标识该请求来源于微信
signature,它的生成方式是将nonce、timestamp和token进行字典排序后进行hash 算法加密得到的
前面我们完成了微信服务器与开发者服务器的相互认证过程
D: 编写服务器业务(文本信息为例)
用户在公众号页面发送请求后,微信服务器会将这条消息封装成如下的XML格式,通过面向对象的思想
分析xml 结构构建相应的实体类 通第三方 XStream 将传过来数据封装成指定格式的xml
微信服务器会将这条消息封装成如下的XML格式,并将其作为请求的内容向开发者服务器发起一个POST请求:
E: access_token :有效期目前为2个小时,需定时刷新 过期后5分钟也可以使用
微信服务器发起post请求将处理后的内容借由微信服务器返回给用户
获取token是给指定的https连接中发送了一个get请求 携带APPID APPSECRET
这个token中包含了两个参数一个是我们使用的token 一个是有效时间
F: 通过生产的token 可以使用各个接口实现具体的功能
自定义菜单; https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
通过文档给出的json 格式 设计对应的实体类 在通过 JSONObject 将对象转化为 json
请使用https协议给指定的地址 发送了post请求( 这个地址包含token) 发送的时候将我自定义的
json字符串带入(一级菜单有最多三个, 二级菜单1-5)
自定义菜单完后设置时间推送
点击事件 type=event
跳转链接事件 type = view
弹出相册和发图器的事件 type = pic_photo_or_album
微信APP支付接口设计流程
微信支付官方文档地址:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_3
1:前期准备
1:申请微信开放平台账号,获得AppID和AppSecret
2:接下来申请微信支付接口获取微信商户平台的账号,密码以及商户号
3:支付接入
统一下单 ,后台生成支付参数 ,通过支付参数唤醒支付宝支付服务, 端异步回调处理支付结果
构建微信订单参数,自动转换为XML。创建一个java 对象(微信订单所需要的参数) @XStreamAlias("xml")
用这个注解来讲对象转为对应的XML进行请求。调用统一下单接口,获取"预支付交易会话标识
返回 success 向对应的日志表中插入数据。但是这个时候并么有支付成功,访问我们的回调地址,
调用回调地址
获取支付的订单信息
WxPayOrderNotifyResult result = wxPayService.parseOrderNotifyResult(xmlResult);
1,解析获取我们请求的XMl 当return_code = success 的时候处理业务
2,获取 微信支付订单号,商户订单号修改订单信息
3,修改订单信息成功返回 result_msg(返回成功)
3,return WxPayNotifyResponse.success("处理成功");
@AppLogin
@PostMapping("/payOrder")
@ApiOperation("订单支付")
public R payOrder(HttpServletRequest request,
@ApiParam(required = true, name = "orderId", value = "订单ID") @RequestParam(value = "orderId", required = false) String orderId,
@ApiParam(required = true, name = "totalPrice", value = "订单总价") @RequestParam(value = "totalPrice", required = false) String totalPrice,
@ApiParam(required = true, name = "paymentType", value = "支付类型(1微信,2支付宝)") @RequestParam(value = "paymentType", required = false) String paymentType
) {
try {
//获取头部请求信息中的token 根据token获取userID
String headValue = request.getHeader("APPToken");
Claims claims = jwtUtils.getClaimByToken(headValue);
String userId = claims.getSubject().toString();
//微信支付
if(paymentType.equals(PayType.WECHAT.getCode())){
//构造微信支付订单参数
WxPayConfig wxConfig = new WxPayConfig();
WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
orderRequest.setNonceStr(PublicUtil.getRandomString(32));
orderRequest.setBody("微信支付");
orderRequest.setOutTradeNo(orderId);
orderRequest.setTotalFee(WxPayUnifiedOrderRequest.yuanToFen(totalPrice));
orderRequest.setTradeType("APP");
orderRequest.setSpbillCreateIp(IPUtils.getIpAddr(request));
orderRequest.setNotifyUrl(wxConfig.getNotifyUrl());
//调用统一下单接口,获取"预支付交易会话标识"
WxPayUnifiedOrderResult result = wxPayService.unifiedOrder(orderRequest);
if("SUCCESS".equals(result.getReturnCode())){
WxPayAppOrderResult orderResult = wxPayService.createOrder(orderRequest);
logger.info("调用微信预下单接口返回信息:{}", orderResult);
return R.ok().put("result",orderResult);
} else {
return R.error("获取预支付订单失败");
}
}
}
微信支付扫码支付
1,商户必须在公众平台后台设置支付回调URL,用户扫码后微信支付系统回调的productid和openid
2,生成二维码规则连接(公众号appid,商户mch_id,时间戳time_stamp,随机数nonce_str,商品product_id,签名sign)
用StringBuilder 拼接,将key value放入map 集合中按指定的连接规则拼接用这个字符串生成二维码
3,发起对商户后台系统配置的回调URL地址根据接收的数据生成支付订单(调用请求将带productid和用户的openid等参数)
//构造微信支付订单参数 订单参数中有 支付类型,回调地址,订单号,缴费金额
4, 调用统一下单接口,获取"预支付交易会话标识"prepay_id
4,调用统一下单接口后判断 return_code == success(此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断)
5,写入订单记录(么有支付成功)
回调地址代码
/**
* 微信支付回调
* @param request
* @param response
* @throws Exception
*/
@ApiOperation("微信支付回调")
@PostMapping("/wxPayNotify")
@Transactional
public String wxPayNotify(HttpServletRequest request, HttpServletResponse response)throws Exception{
try {
String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
WxPayOrderNotifyResult result = wxPayService.parseOrderNotifyResult(xmlResult);
if("SUCCESS".equals(result.getReturnCode())){
String orderId = result.getOutTradeNo();
String tradeNo = result.getTransactionId();
//查询订单
Recharge info = rechargeService.selectByOrderSn(orderId);
if(info != null){
int flag = rechargeService.updateRecharge(info.getRechargeId(),info.getUserId(),info.getCoin(),1,tradeNo);
if(flag>0){
logger.info("订单号:"+orderId+"状态修改成功");
}else{
logger.info("订单号:"+orderId+"状态修改失败");
}
}else{
logger.info("订单号:"+orderId+"不存在");
}
}
return WxPayNotifyResponse.success("处理成功!");
} catch (Exception e) {
logger.error("微信回调结果异常,异常原因{}", e.getMessage());
return WxPayNotifyResponse.fail(e.getMessage());
}
}
微信支付具体配置
/**
* 微信支付配置
*/
@Configuration
@ConditionalOnClass(WxPayService.class)
public class WxPayConfiguration {
@Autowired
PaymentMethodService paymentMethodService;
@Bean
@ConditionalOnMissingBean
public WxPayConfig payConfig() {
PaymentMethod method = paymentMethodService.findByPcode("wxpay");
WeixinConfig weixinConfig= JsonUtils.jsonToPojo(method.getParams(), WeixinConfig.class);
WxPayConfig payConfig = new WxPayConfig();
payConfig.setAppId(weixinConfig.getAppId());
payConfig.setMchId(weixinConfig.getMchId());
payConfig.setMchKey(weixinConfig.getPaternerKey());
payConfig.setSubAppId(StringUtils.trimToNull(null));
payConfig.setSubMchId(StringUtils.trimToNull(null));
payConfig.setKeyPath(null);
payConfig.setNotifyUrl(weixinConfig.getUrl());
return payConfig;
}
@Bean
public WxPayService wxPayService(WxPayConfig payConfig) {
WxPayService wxPayService = new WxPayServiceImpl();
wxPayService.setConfig(payConfig);
return wxPayService;
}
}
支付业务接口编写
微信支付的具体流程
我说一下微信支付的一个大概流程,用户在点击提交订单之后进入支付页面,在页面中选择微信支付,
商家后台生成订单调用统一下单api(统一下单可以生成一个预支付的url),
我们通过HttpClient工具类实现对远程微信支付接口的调用。(公众账号ID、商户号、商户订单号、签名)。
(先将这些参数封装在map集合中再转成xml格式通过httpclient发送出去)
微信支付系统将生成的预支付的链接返回给商家后台,商家后台根据这个链接生成一个二维码图片(使用一个插件可以生成二维码图片prious)
展示给用户,
用户打开微信扫一扫二维码,用户输入密码完成支付交易,商家后台循环调用查询订单api通过HttpClient工具类远程调用微信支付系统
(公众账号ID、商户号、签名、商户订单号),将支付状态返回给商家后台,商家后台再将状态返回给前端,前端根据不同的支付状态跳转
不同的页面。为了不让这个循环不停的循环下去,我们又进行了一个超时处理,不然会对服务器造成很大的压力。(比如设置一个变量,每次加一,
当超过某个次数就认为其超时了)。
在用户下订单时,判断如果为微信支付,
就向支付日志表添加一条记录,信息包括支付总金额、订单ID(多个)、用户ID 、下单时间等信息,
支付状态为0(未支付)
生成的支付日志对象放入redis中,以用户ID作为key,这样在生成支付二维码时就可以从redis中提取支付日志对象中的金额和订单号。
当用户支付成功后,修改支付日志的支付状态为1(已支付),并记录微信传递给我们的交易流水号。根据订单ID(多个)修改订单的状态为2
(已付款)