xin
2025-06-04 061a01ce068bf8e1260b6ea8e5c610737185916a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package com.oying.modules.security.service;
 
import com.alibaba.fastjson2.JSONObject;
import com.oying.modules.security.config.WeiXinProperties;
import com.oying.modules.system.domain.User;
import com.oying.modules.system.domain.UserSubscribe;
import com.oying.modules.system.service.UserService;
import com.oying.modules.system.service.UserSubscribeService;
import com.oying.utils.HttpRequest;
import com.oying.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
 
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
 
@Service
@Slf4j
public class WeiXinService {
 
    @Resource
    private WeiXinProperties weiXinProperties;
    @Resource
    private RedisUtils redisUtils;
    @Value("${wx.enabled}")
    private Boolean wxEnabled;
    @Resource
    private UserSubscribeService subscribeService;
    @Resource
    private UserService userService;
 
    /**
     * POST 获取稳定版接口调用凭据 获取小程序全局唯一后台接口调用凭据,token有效期为7200s,开发者需要进行妥善保存。
     *
     * @return accessToken
     */
    public String getStableAccessToken() {
        String accessToken;
        if (redisUtils.isExpire(weiXinProperties.getTokenKey())) {
            // 获取接口调用凭据
            String url = weiXinProperties.getGetStableAccessToken();
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("grant_type", "client_credential");
            map.put("appid", weiXinProperties.getAppId());
            map.put("secret", weiXinProperties.getAppSecret());
            map.put("force_refresh", false);
            JSONObject jsonObject = HttpRequest.exchangeJsonObject(HttpMethod.POST, url, map);
            accessToken = jsonObject.getString("access_token");
            redisUtils.set(weiXinProperties.getTokenKey(), accessToken, weiXinProperties.getTokenTime());
        } else {
            // 查询接口调用凭据
            accessToken = (String) redisUtils.get(weiXinProperties.getTokenKey());
        }
        return accessToken;
    }
 
    /**
     * GET 小程序登录 登录凭证校验。通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程
     *
     * @param js_code 登录时获取的 code,可通过wx.login获取
     * @return JSONObject
     */
    public JSONObject code2Session(String js_code) {
        String url = weiXinProperties.getCode2Session();
        url = url.replace("{appid}", weiXinProperties.getAppId())
                .replace("{secret}", weiXinProperties.getAppSecret())
                .replace("{js_code}", js_code);
        return HttpRequest.exchangeJsonObject(HttpMethod.GET, url, null);
    }
 
    /**
     * POST 获取手机号 该接口用于将code换取用户手机号。 说明,每个code只能使用一次,code的有效期为5min。
     *
     * @param code 手机号获取凭证
     * @return JSONObject
     */
    public JSONObject getPhoneNumber(String code) {
        String url = weiXinProperties.getGetPhoneNumber();
        url = url.replace("{accessToken}", getStableAccessToken());
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("code", code);
        return HttpRequest.exchangeJsonObject(HttpMethod.POST, url, map);
    }
 
    /**
     * POST 该接口用于发送订阅消息。
     *
     * @param data       请求参数
     * @param openid     用户openId
     * @param templateId 订阅模板id
     * @param page       小程序跳转链接
     */
    public void sendMessage(Map<String, Object> data, String openid, String templateId, String page) {
        JSONObject jsonObject = new JSONObject();
        if (wxEnabled) {
            String url = weiXinProperties.getSendMessage();
            url = url.replace("{accessToken}", getStableAccessToken());
            Map<String, Object> map = getSendMessageDto(data, openid, templateId, page);
            jsonObject = HttpRequest.exchangeJsonObject(HttpMethod.POST, url, map);
        } else {
            jsonObject.put("message", "测试环境");
        }
        User user = userService.findByOpenid(openid);
        UserSubscribe sub = new UserSubscribe();
        sub.setSubType(templateId);
        sub.setUserId(user.getId());
        sub.setOpenid(openid);
        sub.setUsername(user.getUsername());
        sub.setSendMessage(JSONObject.toJSONString(data));
        sub.setSubMessage(jsonObject.toJSONString());
        subscribeService.save(sub);
    }
 
    private Map<String, Object> getSendMessageDto(Map<String, Object> data, String openId, String templateId, String page) {
        Map<String, Object> map = new HashMap<>();
        map.put("touser", openId);
        map.put("template_id", templateId);
        map.put("page", page);
        map.put("miniprogram_state", weiXinProperties.getMiniProgramState());
        map.put("lang", "zh_CN");
        map.put("data", data);
        return map;
    }
}