WxMiniProgramHttpClient.java
6.11 KB
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
129
package com.infoloop.tianting.service.client;
import com.infoloop.tianting.model.dto.WxUserDto.WxUserOpenIdDto;
import com.infoloop.tianting.model.dto.WxUserDto.WxUserPhoneResponseDto;
import com.infoloop.tianting.model.dto.WxUserDto.WxUserTokenDto;
import com.infoloop.tianting.store.WxAccessTokenStore;
import com.infoloop.tianting.utils.JsonUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;
import static com.infoloop.tianting.constant.ConfigConstants.MINI_PROGRAM_APP_ID;
import static com.infoloop.tianting.constant.ConfigConstants.MINI_PROGRAM_APP_SECRET;
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class WxMiniProgramHttpClient {
private static final String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appId}&secret={appSecret}";
private static final String PHONE_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={accessToken}";
private final RestTemplate restTemplate;
private final WxAccessTokenStore wxAccessTokenStore;
@Value(MINI_PROGRAM_APP_ID)
private String appId;
@Value(MINI_PROGRAM_APP_SECRET)
private String appSecret;
public WxUserPhoneResponseDto getUserPhoneInfoByCode(String code) {
try {
String accessToken = fetchStableAccessToken();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
Map<String, Object> jsonDataMap = new HashMap<>();
jsonDataMap.put("code", code);
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(jsonDataMap, headers);
return fetchPhoneNumber(accessToken, requestEntity);
} catch (Exception e) {
log.error("Error fetching user phone info", e);
throw new IllegalArgumentException("获取用户手机号失败");
}
}
private String fetchAccessToken() {
log.info("Fetching WeChat access token...");
final var code = wxAccessTokenStore.getAccessToken();
if (StringUtils.isNotEmpty(code)) {
log.info("Using cached access token: {}", code);
return code;
}
ResponseEntity<String> tokenResponse = restTemplate.getForEntity(TOKEN_URL, String.class, appId, appSecret);
if (!tokenResponse.getStatusCode().is2xxSuccessful() || tokenResponse.getBody() == null) {
log.error("Failed to fetch access token: {}", tokenResponse);
throw new IllegalArgumentException("获取 access_token 失败");
}
final var wxUserTokenDto = JsonUtil.readJsonAs(tokenResponse.getBody(), WxUserTokenDto.class);
log.info("WeChat access token received: {}", wxUserTokenDto);
final var accessToken = wxUserTokenDto.getAccess_token();
wxAccessTokenStore.setAccessToken(accessToken);
return accessToken;
}
public String fetchStableAccessToken() {
log.info("Fetching WeChat access token...");
final var code = wxAccessTokenStore.getAccessToken();
if (StringUtils.isNotEmpty(code)) {
log.info("Using cached access token: {}", code);
return code;
}
String url = "https://api.weixin.qq.com/cgi-bin/stable_token";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
Map<String, String> requestBody = new HashMap<>();
requestBody.put("grant_type", "client_credential");
requestBody.put("appid", appId);
requestBody.put("secret", appSecret);
HttpEntity<Map<String, String>> request = new HttpEntity<>(requestBody, headers);
ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
if (!response.getStatusCode().is2xxSuccessful() || response.getBody() == null) {
log.error("Failed to fetch access token: {}", response);
throw new IllegalArgumentException("获取 access_token 失败");
}
WxUserTokenDto tokenDto = JsonUtil.readJsonAs(response.getBody(), WxUserTokenDto.class);
log.info("WeChat access token received: {}", tokenDto);
final var accessToken = tokenDto.getAccess_token();
wxAccessTokenStore.setAccessToken(accessToken);
return accessToken;
}
private WxUserPhoneResponseDto fetchPhoneNumber(String accessToken, HttpEntity<Map<String, Object>> requestEntity) {
log.info("Fetching phone number...");
ResponseEntity<WxUserPhoneResponseDto> phoneResponse = restTemplate.exchange(PHONE_URL, HttpMethod.POST, requestEntity, WxUserPhoneResponseDto.class, accessToken);
if (!phoneResponse.getStatusCode().is2xxSuccessful() || phoneResponse.getBody() == null) {
log.error("Failed to fetch phone number: {}", phoneResponse);
throw new IllegalArgumentException("获取手机号失败");
}
log.info("WeChat phone number response: {}", phoneResponse.getBody());
return phoneResponse.getBody();
}
public WxUserOpenIdDto getUserOpenIdByCode(String code) {
try {
final var url = "https://api.weixin.qq.com/sns/jscode2session" +
"?appid=" + appId + "&secret=" + appSecret + "&js_code=" + code + "&grant_type=authorization_code";
final var response = restTemplate.getForEntity(url, String.class);
return JsonUtil.readJsonAs(response.getBody(), WxUserOpenIdDto.class);
} catch (Exception e) {
log.error("Error fetching user openid", e);
throw new IllegalArgumentException("获取用户openid失败");
}
}
}