Skip to content

Commit

Permalink
实现accessToken接口
Browse files Browse the repository at this point in the history
  • Loading branch information
dbstarll committed May 15, 2023
1 parent 6d77df9 commit 6cead3e
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/main/java/io/github/dbstarll/weixin/sdk/SecretHolder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.github.dbstarll.weixin.sdk;

public interface SecretHolder {
/**
* 根据AppId获得Secret.
*
* @param appId appId
* @return appId对应的secret
*/
String getSecret(String appId);
}
80 changes: 80 additions & 0 deletions src/main/java/io/github/dbstarll/weixin/sdk/WeChatApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package io.github.dbstarll.weixin.sdk;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.github.dbstarll.utils.http.client.request.RelativeUriResolver;
import io.github.dbstarll.utils.json.jackson.JsonApiClient;
import io.github.dbstarll.utils.net.api.ApiException;
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.core5.http.ClassicHttpRequest;
import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;

import java.io.IOException;

import static org.apache.commons.lang3.Validate.notBlank;
import static org.apache.commons.lang3.Validate.notNull;

public class WeChatApi extends JsonApiClient {
private final SecretHolder secretHolder;

/**
* 构造WeChatApi.
*
* @param httpClient httpClient
* @param objectMapper objectMapper
* @param secretHolder SecretHolder
*/
public WeChatApi(final HttpClient httpClient, final ObjectMapper objectMapper, final SecretHolder secretHolder) {
super(httpClient, true, objectMapper);
this.secretHolder = notNull(secretHolder, "secretHolder not set");
setUriResolver(new RelativeUriResolver("https://api.weixin.qq.com"));
}

@Override
protected <T> T postProcessing(final ClassicHttpRequest request, final T executeResult) throws ApiException {
final T superResult = super.postProcessing(request, executeResult);
if (superResult instanceof ObjectNode) {
final ObjectNode node = (ObjectNode) superResult;
final int errcode = node.path("errcode").asInt(0);
if (errcode != 0) {
throw new WeChatResponseException(errcode, node.path("errmsg").asText());
}
}
return superResult;
}

/**
* 登录凭证校验.
*
* @param appId 小程序 appId
* @param code 登录时获取的 code
* @return 登录凭证
* @throws IOException in case of a problem or the connection was aborted
* @throws ApiException in case of an api error
*/
public ObjectNode session(final String appId, final String code) throws IOException, ApiException {
return execute(auth(post("/sns/jscode2session")
.addParameter("grant_type", "authorization_code")
.addParameter("js_code", notBlank(code, "code not set")), appId), ObjectNode.class);
}

/**
* 获取小程序全局唯一后台接口调用凭据,token有效期为7200s,开发者需要进行妥善保存.
*
* @param appId 小程序唯一凭证,即 AppID,可在「微信公众平台 - 设置 - 开发设置」页中获得
* @return 接口调用凭据
* @throws IOException in case of a problem or the connection was aborted
* @throws ApiException in case of an api error
*/
public ObjectNode accessToken(final String appId) throws IOException, ApiException {
return execute(auth(get("/cgi-bin/token")
.addParameter("grant_type", "client_credential"), appId), ObjectNode.class);
}

private ClassicHttpRequest auth(final ClassicRequestBuilder builder, final String appId) {
return builder
.addParameter("appid", notBlank(appId, "appId not set"))
.addParameter("secret", notBlank(secretHolder.getSecret(appId), "secret not found for {}", appId))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.github.dbstarll.weixin.sdk;

import io.github.dbstarll.utils.net.api.ApiResponseException;
import org.apache.commons.lang3.StringUtils;
import org.apache.hc.client5.http.HttpResponseException;

public class WeChatResponseException extends ApiResponseException {
private static final String RID_SPLIT_TOKEN = " rid: ";

private final String rid;

/**
* 构建WeChatResponseException.
*
* @param errCode 错误码
* @param errMsg 错误信息
*/
public WeChatResponseException(final int errCode, final String errMsg) {
super(new HttpResponseException(errCode, StringUtils.substringBefore(errMsg, RID_SPLIT_TOKEN)));
this.rid = StringUtils.substringAfter(errMsg, RID_SPLIT_TOKEN);
}

/**
* 获得rid信息.
*
* @return rid信息
*/
public final String getRid() {
return rid;
}
}
42 changes: 42 additions & 0 deletions src/test/java/io/github/dbstarll/weixin/sdk/WeChatApiTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.github.dbstarll.weixin.sdk;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.dbstarll.utils.http.client.HttpClientFactory;
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.ThrowingConsumer;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;

class WeChatApiTest {
private void useClient(final ThrowingConsumer<HttpClient> consumer) throws Throwable {
try (CloseableHttpClient client = new HttpClientFactory().build()) {
consumer.accept(client);
}
}

private void useApi(final ThrowingConsumer<WeChatApi> consumer, final SecretHolder secretHolder) throws Throwable {
useClient(httpClient -> consumer.accept(new WeChatApi(httpClient, new ObjectMapper(), secretHolder)));
}

@Test
void nullSecretHolder() {
final Exception e = assertThrowsExactly(NullPointerException.class,
() -> useApi(api -> {
}, null));
assertEquals("secretHolder not set", e.getMessage());
}

@Test
void accessToken() throws Throwable {
useApi(api -> {
final WeChatResponseException e = assertThrowsExactly(WeChatResponseException.class, () -> api.accessToken("appId"));
assertEquals(40013, e.getStatusCode());
assertEquals("invalid appid", e.getReasonPhrase());
assertNotNull(e.getRid());
}, appId -> "secret");
}
}

0 comments on commit 6cead3e

Please sign in to comment.