# 微信小程序

# 微信小程序获取phoneNumber,openId,nickName,avatarUrl


package com.common;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

/**
 * 功能描述:
 *
 * @author 拓金辉
 * @version 1.0
 * @date 2021-10-26 15:03:01
 */
@Getter
@Setter
@Schema(description = "小程序登录")
public class WxMaLoginRequest {

    @Schema(description = "小程序 [wx.login]。 用户登录凭证(有效期五分钟)。开发者需要在开发者服务器后台调用 auth.code2Session,使用 code 换取 openid、unionid、session_key 等信息")
    private String code;

    @Valid
    @NotNull
    @Schema(description = "小程序登录getUserInfo")
    private GetUserInfo getUserInfo;

    @Valid
    @NotNull
    @Schema(description = "小程序登录getPhoneNumber")
    private GetPhoneNumber getPhoneNumber;

    @Getter
    @Setter
    @Schema(description = "小程序登录getUserInfo")
    public static class GetUserInfo {

        @NotBlank
        @Schema(description = "小程序 [open-type='getUserInfo'] 返回的加密数据")
        private String encryptedData;

        @NotBlank
        @Schema(description = "小程序 [open-type='getUserInfo'] 返回的加密算法的初始向量")
        private String iv;
        
    }

    @Getter
    @Setter
    @Schema(description = "小程序登录getPhoneNumber")
    public static class GetPhoneNumber {

        @NotBlank
        @Schema(description = "小程序 [open-type='getPhoneNumber'] 返回的加密数据")
        private String encryptedData;

        @NotBlank
        @Schema(description = "小程序 [open-type='getPhoneNumber'] 返回的加密算法的初始向量")
        private String iv;
        
    }

}


        final String code = request.getCode();
        final WxMaLoginRequest.GetUserInfo getUserInfo = request.getGetUserInfo();
        final WxMaLoginRequest.GetPhoneNumber getPhoneNumber = request.getGetPhoneNumber();

        final WxMaJscode2SessionResult wxMaJscode2SessionResult = wxMaService.jsCode2SessionInfo(code);
        final String sessionKey = wxMaJscode2SessionResult.getSessionKey();
        final WxMaUserService userService = wxMaService.getUserService();
        final WxMaUserInfo wxMaUserInfo = userService.getUserInfo(sessionKey, getUserInfo.getEncryptedData(), getUserInfo.getIv());
        final WxMaPhoneNumberInfo wxMaPhoneNumberInfo = userService.getPhoneNoInfo(sessionKey, getPhoneNumber.getEncryptedData(), getPhoneNumber.getIv());


# 微信小程序生成 URL Scheme

urlscheme.generate (opens new window)


    // "pages/index/index"

    @Resource
    private WxMaService wxMaService;

    public String genSchemeUrl(String appId, String path, String query) {
        try {
            log.debug("生成小程序URL Scheme, appId:{}, path:{}, query:{}", appId, path, query);
            WxMaService wxMaService = this.wxMaService.switchoverTo(appId);
            final WxMaSchemeService wxMaSchemeService = wxMaService.getWxMaSchemeService();
            WxMaGenerateSchemeRequest wxMaGenerateSchemeRequest = WxMaGenerateSchemeRequest.newBuilder().build();
            WxMaGenerateSchemeRequest.JumpWxa jumpWxa = WxMaGenerateSchemeRequest.JumpWxa.newBuilder().build();
            jumpWxa.setPath(path);
            jumpWxa.setQuery(query);
            wxMaGenerateSchemeRequest.setIsExpire(true);
            wxMaGenerateSchemeRequest.setExpireTime(LocalDateTime.now().plusMonths(1L).toEpochSecond(ZoneOffset.ofHours(8)));
            wxMaGenerateSchemeRequest.setJumpWxa(jumpWxa);
            return wxMaSchemeService.generate(wxMaGenerateSchemeRequest);
        } catch (WxErrorException e) {
            log.error("生成小程序URL Scheme错误, 异常信息={}", e.getMessage(), e);
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        } finally {
            WxMaConfigHolder.remove();
        }
    }

# 微信小程序扫普通链接二维码打开体验版小程序


    /**
     * 扫描二维码到体验版
     */
    public static final String SCAN_QR_CODE_TRIAL = "https://open.weixin.qq.com/sns/getexpappinfo?appid=%s&path=%s.html?q=%s";

WARNING

跳转页面的动态参数只能携带一个且只能是q,携带其它参数会认为是 open.weixin.qq.com链接的参数,故而跳转携带无效。解决办法:携带q参数,参数值进行url编码并json序列化处理

# 微信小程序扫码绑定openId


package com.common;

import com.google.common.collect.ImmutableMap;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;

/**
 * 功能描述:二维码Session会话
 *
 * @author 拓金辉
 * @version 1.0
 * @date 2021-11-01 14:48:07
 */

@Setter
@Accessors(chain = true)
public class Session {

    private ImmutableMap<String, String> immutable = ImmutableMap.of(UN_SCAN, "待扫码", SCANNED, "已扫码", CONFIRMED, "已确认", CANCELLED, "已取消", EXPIRED, "已过期");
    public static final String QR_CODE_SESSION_ID = "qrCodeSessionId";
    public static final String QR_CODE_URL = "qrCodeUrl";
    public static final String UN_SCAN = "1";
    public static final String SCANNED = "2";
    public static final String CONFIRMED = "3";
    public static final String CANCELLED = "4";
    public static final String EXPIRED = "5";

    @Getter
    @Schema(description = "二维码会话码")
    private String code;

    @Getter
    @Schema(description = "二维码会话描述")
    private String message;

    @Getter
    @Schema(description = "二维码会话数据集")
    private SessionData data;

    /**
     * 方法描述:每次二维码会话码变更调用此方法
     *
     * @param code 会话码
     * @author 拓金辉
     * @date 2021-11-22 15:10:38
     */
    public Session update(String code) {
        if (!immutable.containsKey(code)) {
            throw new IllegalArgumentException(String.format("非法的二维码code:%s", code));
        }
        return this.setCode(code).setMessage(immutable.get(code));
    }

    /**
     * 功能描述:会话数据存储
     *
     * @author 拓金辉
     * @date 2021-11-22 15:10:38
     */
    @Getter
    @Setter
    @Accessors(chain = true)
    public static class SessionData {
        private String qrCodeSessionId;
        private String qrCodeUrl;
        private String nickName;
        private String avatarUrl;
        private String openId;
        private String unionId;

        // 扩展数据存储
        private Object extend;
    }

}

# 微信小程序消息订阅


   /**
     * 方法描述:发送订阅消息
     * <a href="https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html"></a>
     *
     * @param appId            微信小程序appId
     * @param toUSer           接收者(用户)的 openid
     * @param templateId       所需下发的订阅模板id
     * @param page             点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
     * @param miniProgramState 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
     * @param data             模板内容,格式形如 { "key1": { "value": any }, "key2": { "value": any } }
     * @return java.lang.Boolean
     * @author 拓金辉
     * @date 2021-08-11 14:09:20
     */
    public Boolean sendSubscribeMsg(String appId, String toUSer, String templateId, String page, String miniProgramState, List<WxMaSubscribeMessage.MsgData> data) throws WxErrorException {
        try {
            final WxMaService wxMaService = this.wxMaService.switchoverTo(appId);
            final WxMaMsgService msgService = wxMaService.getMsgService();
            WxMaSubscribeMessage wxMaSubscribeMessage = new WxMaSubscribeMessage();
            wxMaSubscribeMessage.setToUser(toUSer);
            wxMaSubscribeMessage.setTemplateId(templateId);
            wxMaSubscribeMessage.setPage(page);
            wxMaSubscribeMessage.setMiniprogramState(miniProgramState);
            wxMaSubscribeMessage.setLang(WxMaConstants.MiniProgramLang.ZH_CN);
            wxMaSubscribeMessage.setData(new ArrayList<>());
            wxMaSubscribeMessage.getData().addAll(data);
            msgService.sendSubscribeMsg(wxMaSubscribeMessage);
            return Boolean.TRUE;
        } finally {
            WxMaConfigHolder.remove();
        }
    }

# 微信小程序支付

微信小程序支付