🆕 【开放平台】接入小程序认证(年审)相关接口,同时增加公共的文件上传方法

This commit is contained in:
天朝红雨 2024-01-12 20:01:42 +08:00 committed by GitHub
parent d957896ac1
commit 774579186c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 1353 additions and 270 deletions

View File

@ -2,36 +2,19 @@ package me.chanjar.weixin.channel.api.impl;
import com.google.gson.JsonObject;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.channel.api.WxChannelAddressService;
import me.chanjar.weixin.channel.api.WxChannelAfterSaleService;
import me.chanjar.weixin.channel.api.WxChannelBasicService;
import me.chanjar.weixin.channel.api.WxChannelBrandService;
import me.chanjar.weixin.channel.api.WxChannelCategoryService;
import me.chanjar.weixin.channel.api.WxChannelCouponService;
import me.chanjar.weixin.channel.api.WxChannelFreightTemplateService;
import me.chanjar.weixin.channel.api.WxChannelFundService;
import me.chanjar.weixin.channel.api.WxChannelOrderService;
import me.chanjar.weixin.channel.api.WxChannelProductService;
import me.chanjar.weixin.channel.api.WxChannelService;
import me.chanjar.weixin.channel.api.WxChannelSharerService;
import me.chanjar.weixin.channel.api.WxChannelWarehouseService;
import me.chanjar.weixin.channel.api.WxLeagueProductService;
import me.chanjar.weixin.channel.api.WxLeaguePromoterService;
import me.chanjar.weixin.channel.api.WxLeagueSupplierService;
import me.chanjar.weixin.channel.api.WxLeagueWindowService;
import me.chanjar.weixin.channel.api.*;
import me.chanjar.weixin.channel.config.WxChannelConfig;
import me.chanjar.weixin.channel.util.JsonUtils;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.CommonUploadParam;
import me.chanjar.weixin.common.bean.ToJson;
import me.chanjar.weixin.common.bean.WxAccessToken;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.error.WxRuntimeException;
import me.chanjar.weixin.common.executor.CommonUploadRequestExecutor;
import me.chanjar.weixin.common.util.DataUtils;
import me.chanjar.weixin.common.util.crypto.SHA1;
import me.chanjar.weixin.common.util.http.RequestExecutor;
@ -40,6 +23,10 @@ import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
/**
* @author <a href="https://github.com/lixize">Zeyes</a>
* @see #doGetAccessTokenRequest
@ -119,7 +106,6 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
* 通过网络请求获取AccessToken
*
* @return .
*
* @throws IOException .
*/
protected abstract String doGetAccessTokenRequest() throws IOException;
@ -145,6 +131,12 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
return this.post(url, obj.toJson());
}
@Override
public String upload(String url, CommonUploadParam param) throws WxErrorException {
RequestExecutor<String, CommonUploadParam> executor = CommonUploadRequestExecutor.create(getRequestHttp());
return this.execute(executor, url, param);
}
@Override
public String post(String url, JsonObject jsonObject) throws WxErrorException {
return this.post(url, jsonObject.toString());
@ -200,7 +192,7 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
}
protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data, boolean doNotAutoRefreshToken,
boolean printResult) throws WxErrorException {
boolean printResult) throws WxErrorException {
E dataForLog = DataUtils.handleDataWithSecret(data);
if (uri.contains("access_token=")) {
@ -259,7 +251,6 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
*
* @param resultContent 响应内容
* @return access token
*
* @throws WxErrorException 异常
*/
protected String extractAccessToken(String resultContent) throws WxErrorException {
@ -372,7 +363,7 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
}
@Override
public synchronized WxLeaguePromoterService getLeaguePromoterService() {
public synchronized WxLeaguePromoterService getLeaguePromoterService() {
if (leaguePromoterService == null) {
leaguePromoterService = new WxLeaguePromoterServiceImpl(this);
}

View File

@ -0,0 +1,76 @@
package me.chanjar.weixin.common.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.lang.Nullable;
import java.io.*;
import java.nio.file.Files;
/**
* 通用文件上传数据
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
@Slf4j
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommonUploadData implements Serializable {
/**
* 文件名1.jpg
*/
@Nullable
private String fileName;
/**
* 文件内容
*
* @see FileInputStream 文件输入流
* @see ByteArrayInputStream 字节输入流
*/
@NotNull
private InputStream inputStream;
/**
* 文件内容长度(字节数)
*/
private long length;
/**
* 从文件构造
*
* @param file 文件
* @return 通用文件上传数据
*/
@SneakyThrows
public static CommonUploadData fromFile(File file) {
return new CommonUploadData(file.getName(), Files.newInputStream(file.toPath()), file.length());
}
/**
* 读取所有字节,此方法会关闭输入流
*
* @return 字节数组
*/
@SneakyThrows
public byte[] readAllBytes() {
byte[] bytes = new byte[(int) length];
//noinspection ResultOfMethodCallIgnored
inputStream.read(bytes);
inputStream.close();
return bytes;
}
@Override
public String toString() {
return String.format("{fileName:%s, length:%s}", fileName, length);
}
}

View File

@ -0,0 +1,65 @@
package me.chanjar.weixin.common.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import org.jetbrains.annotations.NotNull;
import org.springframework.lang.Nullable;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.Serializable;
/**
* 通用文件上传参数
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommonUploadParam implements Serializable {
/**
* 文件对应的接口参数名称(非文件名)media
*/
@NotNull
private String name;
/**
* 上传数据
*/
@NotNull
private CommonUploadData data;
/**
* 从文件构造
*
* @param name 参数名media
* @param file 文件
* @return 文件上传参数对象
*/
@SneakyThrows
public static CommonUploadParam fromFile(String name, File file) {
return new CommonUploadParam(name, CommonUploadData.fromFile(file));
}
/**
* 从字节数组构造
*
* @param name 参数名media
* @param bytes 字节数组
* @return 文件上传参数对象
*/
@SneakyThrows
public static CommonUploadParam fromBytes(String name, @Nullable String fileName, byte[] bytes) {
return new CommonUploadParam(name, new CommonUploadData(fileName, new ByteArrayInputStream(bytes), bytes.length));
}
@Override
public String toString() {
return String.format("{name:%s, data:%s}", name, data);
}
}

View File

@ -0,0 +1,50 @@
package me.chanjar.weixin.common.executor;
import me.chanjar.weixin.common.bean.CommonUploadParam;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.ResponseHandler;
import java.io.IOException;
/**
* 通用文件上传执行器
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
public abstract class CommonUploadRequestExecutor<H, P> implements RequestExecutor<String, CommonUploadParam> {
protected RequestHttp<H, P> requestHttp;
public CommonUploadRequestExecutor(RequestHttp<H, P> requestHttp) {
this.requestHttp = requestHttp;
}
@Override
public void execute(String uri, CommonUploadParam data, ResponseHandler<String> handler, WxType wxType) throws WxErrorException, IOException {
handler.handle(this.execute(uri, data, wxType));
}
/**
* 构造通用文件上传执行器
*
* @param requestHttp 请求信息
* @return 执行器
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public static RequestExecutor<String, CommonUploadParam> create(RequestHttp requestHttp) {
switch (requestHttp.getRequestType()) {
case APACHE_HTTP:
return new CommonUploadRequestExecutorApacheImpl(requestHttp);
case JODD_HTTP:
return new CommonUploadRequestExecutorJoddHttpImpl(requestHttp);
case OK_HTTP:
return new CommonUploadRequestExecutorOkHttpImpl(requestHttp);
default:
throw new IllegalArgumentException("不支持的http执行器类型" + requestHttp.getRequestType());
}
}
}

View File

@ -0,0 +1,83 @@
package me.chanjar.weixin.common.executor;
import lombok.Getter;
import me.chanjar.weixin.common.bean.CommonUploadData;
import me.chanjar.weixin.common.bean.CommonUploadParam;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.impl.client.CloseableHttpClient;
import java.io.IOException;
import java.io.InputStream;
/**
* Apache HttpClient 通用文件上传器
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
public class CommonUploadRequestExecutorApacheImpl
extends CommonUploadRequestExecutor<CloseableHttpClient, HttpHost> {
public CommonUploadRequestExecutorApacheImpl(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
super(requestHttp);
}
@Override
public String execute(String uri, CommonUploadParam param, WxType wxType) throws WxErrorException, IOException {
HttpPost httpPost = new HttpPost(uri);
if (requestHttp.getRequestHttpProxy() != null) {
RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
httpPost.setConfig(config);
}
if (param != null) {
CommonUploadData data = param.getData();
InnerStreamBody part = new InnerStreamBody(data.getInputStream(), ContentType.DEFAULT_BINARY, data.getFileName(), data.getLength());
HttpEntity entity = MultipartEntityBuilder
.create()
.addPart(param.getName(), part)
.setMode(HttpMultipartMode.RFC6532)
.build();
httpPost.setEntity(entity);
}
try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
if (responseContent == null || responseContent.isEmpty()) {
throw new WxErrorException(String.format("上传失败,服务器响应空 url:%s param:%s", uri, param));
}
WxError error = WxError.fromJson(responseContent, wxType);
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
}
return responseContent;
} finally {
httpPost.releaseConnection();
}
}
/**
* 内部流 请求体
*/
@Getter
public static class InnerStreamBody extends InputStreamBody {
private final long contentLength;
public InnerStreamBody(final InputStream in, final ContentType contentType, final String filename, long contentLength) {
super(in, contentType, filename);
this.contentLength = contentLength;
}
}
}

View File

@ -0,0 +1,91 @@
package me.chanjar.weixin.common.executor;
import jodd.http.HttpConnectionProvider;
import jodd.http.HttpRequest;
import jodd.http.HttpResponse;
import jodd.http.ProxyInfo;
import jodd.http.upload.Uploadable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.SneakyThrows;
import me.chanjar.weixin.common.bean.CommonUploadData;
import me.chanjar.weixin.common.bean.CommonUploadParam;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.RequestHttp;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
/**
* JoddHttp 通用文件上传器
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
public class CommonUploadRequestExecutorJoddHttpImpl extends CommonUploadRequestExecutor<HttpConnectionProvider, ProxyInfo> {
public CommonUploadRequestExecutorJoddHttpImpl(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp) {
super(requestHttp);
}
@Override
public String execute(String uri, CommonUploadParam param, WxType wxType) throws WxErrorException, IOException {
HttpRequest request = HttpRequest.post(uri);
if (requestHttp.getRequestHttpProxy() != null) {
requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy());
}
request.withConnectionProvider(requestHttp.getRequestHttpClient());
request.form(param.getName(), new CommonUploadParamToUploadableAdapter(param.getData()));
HttpResponse response = request.send();
response.charset(StandardCharsets.UTF_8.name());
String responseContent = response.bodyText();
if (responseContent.isEmpty()) {
throw new WxErrorException(String.format("上传失败,服务器响应空 url:%s param:%s", uri, param));
}
WxError error = WxError.fromJson(responseContent, wxType);
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
}
return responseContent;
}
/**
* 通用上传参数 Uploadable 的适配器
*/
@Getter
@AllArgsConstructor
public static class CommonUploadParamToUploadableAdapter implements Uploadable<CommonUploadData> {
private CommonUploadData content;
@SneakyThrows
@Override
public byte[] getBytes() {
return content.readAllBytes();
}
@Override
public String getFileName() {
return content.getFileName();
}
@Override
public String getMimeType() {
return null;
}
@SneakyThrows
@Override
public int getSize() {
return (int) content.getLength();
}
@Override
public InputStream openInputStream() {
return content.getInputStream();
}
}
}

View File

@ -0,0 +1,91 @@
package me.chanjar.weixin.common.executor;
import lombok.AllArgsConstructor;
import me.chanjar.weixin.common.bean.CommonUploadData;
import me.chanjar.weixin.common.bean.CommonUploadParam;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
import okhttp3.*;
import okio.BufferedSink;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.InputStream;
/**
* OkHttp 通用文件上传器
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
public class CommonUploadRequestExecutorOkHttpImpl extends CommonUploadRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
public CommonUploadRequestExecutorOkHttpImpl(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp) {
super(requestHttp);
}
@Override
public String execute(String uri, CommonUploadParam param, WxType wxType) throws WxErrorException, IOException {
RequestBody requestBody = new CommonUpdateDataToRequestBodyAdapter(param.getData());
RequestBody body = new MultipartBody.Builder()
.setType(MediaType.get("multipart/form-data"))
.addFormDataPart(param.getName(), param.getData().getFileName(), requestBody)
.build();
Request request = new Request.Builder().url(uri).post(body).build();
try (Response response = requestHttp.getRequestHttpClient().newCall(request).execute()) {
ResponseBody responseBody = response.body();
String responseContent = responseBody == null ? "" : responseBody.string();
if (responseContent.isEmpty()) {
throw new WxErrorException(String.format("上传失败,服务器响应空 url:%s param:%s", uri, param));
}
WxError error = WxError.fromJson(responseContent, wxType);
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
}
return responseContent;
}
}
/**
* 通用上传输入 OkHttp 请求提 适配器
*/
@AllArgsConstructor
public static class CommonUpdateDataToRequestBodyAdapter extends RequestBody {
private static final MediaType CONTENT_TYPE = MediaType.get("application/octet-stream");
private CommonUploadData data;
@Override
public long contentLength() {
return data.getLength();
}
@Nullable
@Override
public MediaType contentType() {
return CONTENT_TYPE;
}
@Override
public void writeTo(@NotNull BufferedSink bufferedSink) throws IOException {
InputStream inputStream = data.getInputStream();
int count;
byte[] buffer = new byte[4096];
while ((count = inputStream.read(buffer)) != -1) {
bufferedSink.write(buffer, 0, count);
}
inputStream.close();
}
@Override
public boolean isOneShot() {
return true;
}
}
}

View File

@ -1,6 +1,7 @@
package me.chanjar.weixin.common.service;
import com.google.gson.JsonObject;
import me.chanjar.weixin.common.bean.CommonUploadParam;
import me.chanjar.weixin.common.bean.ToJson;
import me.chanjar.weixin.common.error.WxErrorException;
@ -60,4 +61,14 @@ public interface WxService {
* @throws WxErrorException 异常
*/
String post(String url, ToJson obj) throws WxErrorException;
/**
* 当本Service没有实现某个上传API的时候可以用这个针对所有微信API中的POST文件上传请求
*
* @param url 请求接口地址
* @param param 文件上传对象
* @return 接口响应字符串
* @throws WxErrorException 异常
*/
String upload(String url, CommonUploadParam param) throws WxErrorException;
}

View File

@ -1,21 +1,27 @@
package me.chanjar.weixin.common.util.http;
import java.io.File;
import java.io.IOException;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.bean.CommonUploadParam;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.service.WxService;
import me.chanjar.weixin.common.util.http.apache.ApacheMediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaUploadRequestExecutor;
import java.io.File;
import java.io.IOException;
/**
* 上传媒体文件请求执行器.
* 请求的参数是File, 返回的结果是String
*
* @author Daniel Qian
* @see WxService#upload(String, CommonUploadParam) 通用的上传封装接口是推荐调用此方法
* @see CommonUploadParam 通用的上传参数
* @deprecated 不应该继续使用执行器的方式上传文件封装上传接口时应调用通用的文件上传而旧代码也应该逐步迁移为新的上传方式
*/
@Deprecated
public abstract class MediaUploadRequestExecutor<H, P> implements RequestExecutor<WxMediaUploadResult, File> {
protected RequestHttp<H, P> requestHttp;

View File

@ -5,12 +5,14 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.CommonUploadParam;
import me.chanjar.weixin.common.bean.ToJson;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.error.WxRuntimeException;
import me.chanjar.weixin.common.executor.CommonUploadRequestExecutor;
import me.chanjar.weixin.common.session.StandardSessionManager;
import me.chanjar.weixin.common.session.WxSession;
import me.chanjar.weixin.common.session.WxSessionManager;
@ -24,8 +26,6 @@ import me.chanjar.weixin.cp.bean.WxCpAgentJsapiSignature;
import me.chanjar.weixin.cp.bean.WxCpMaJsCode2SessionResult;
import me.chanjar.weixin.cp.bean.WxCpProviderToken;
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
import me.chanjar.weixin.cp.corpgroup.service.WxCpLinkedCorpService;
import me.chanjar.weixin.cp.corpgroup.service.impl.WxCpLinkedCorpServiceImpl;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
@ -268,6 +268,12 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
return this.post(url, obj.toJson());
}
@Override
public String upload(String url, CommonUploadParam param) throws WxErrorException {
RequestExecutor<String, CommonUploadParam> executor = CommonUploadRequestExecutor.create(getRequestHttp());
return this.execute(executor, url, param);
}
@Override
public String post(String url, Object obj) throws WxErrorException {
return this.post(url, obj.toString());

View File

@ -12,12 +12,14 @@ import com.google.gson.Gson;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.CommonUploadParam;
import me.chanjar.weixin.common.bean.ToJson;
import me.chanjar.weixin.common.bean.WxAccessToken;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.error.WxRuntimeException;
import me.chanjar.weixin.common.executor.CommonUploadRequestExecutor;
import me.chanjar.weixin.common.service.WxImgProcService;
import me.chanjar.weixin.common.service.WxOcrService;
import me.chanjar.weixin.common.util.DataUtils;
@ -237,6 +239,12 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
return this.post(url, obj.toJson());
}
@Override
public String upload(String url, CommonUploadParam param) throws WxErrorException {
RequestExecutor<String, CommonUploadParam> executor = CommonUploadRequestExecutor.create(getRequestHttp());
return this.execute(executor, url, param);
}
@Override
public String post(String url, JsonObject jsonObject) throws WxErrorException {
return this.post(url, jsonObject.toString());
@ -378,7 +386,7 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
@JsonDeserialize
public void setMultiConfigs(Map<String, WxMaConfig> configs, String defaultMiniappId) {
// 防止覆盖配置
if(this.configMap != null) {
if (this.configMap != null) {
this.configMap.putAll(configs);
} else {
this.configMap = Maps.newHashMap(configs);
@ -689,7 +697,7 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
}
@Override
public WxMaExpressDeliveryReturnService getWxMaExpressDeliveryReturnService(){
public WxMaExpressDeliveryReturnService getWxMaExpressDeliveryReturnService() {
return this.wxMaExpressDeliveryReturnService;
}
}

View File

@ -3,12 +3,12 @@ package cn.binarywang.wx.miniapp.api.impl;
import cn.binarywang.wx.miniapp.api.WxMaMediaService;
import cn.binarywang.wx.miniapp.api.WxMaService;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.common.bean.CommonUploadParam;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.fs.FileUtils;
import me.chanjar.weixin.common.util.http.BaseMediaDownloadRequestExecutor;
import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import java.io.File;
@ -38,8 +38,10 @@ public class WxMaMediaServiceImpl implements WxMaMediaService {
@Override
public WxMediaUploadResult uploadMedia(String mediaType, File file) throws WxErrorException {
// return this.wxMaService.execute(MediaUploadRequestExecutor.create(this.wxMaService.getRequestHttp()), url, file);
String url = String.format(MEDIA_UPLOAD_URL, mediaType);
return this.wxMaService.execute(MediaUploadRequestExecutor.create(this.wxMaService.getRequestHttp()), url, file);
String result = wxMaService.upload(url, CommonUploadParam.fromFile("media", file));
return WxMediaUploadResult.fromJson(result);
}
@Override

View File

@ -1,58 +0,0 @@
package cn.binarywang.wx.miniapp.executor;
import java.io.File;
import java.io.IOException;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;
import cn.binarywang.wx.miniapp.bean.WxMaAuditMediaUploadResult;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
/**
* @author yangyh22
* @since 2020/11/14
*/
public class ApacheAuditMediaUploadRequestExecutor extends AuditMediaUploadRequestExecutor<CloseableHttpClient, HttpHost> {
public ApacheAuditMediaUploadRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
@Override
public WxMaAuditMediaUploadResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
HttpPost httpPost = new HttpPost(uri);
if (requestHttp.getRequestHttpProxy() != null) {
RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
httpPost.setConfig(config);
}
if (file != null) {
HttpEntity entity = MultipartEntityBuilder
.create()
.addBinaryBody("media", file)
.setMode(HttpMultipartMode.RFC6532)
.build();
httpPost.setEntity(entity);
}
try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
WxError error = WxError.fromJson(responseContent, wxType);
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
}
return WxMaAuditMediaUploadResult.fromJson(responseContent);
} finally {
httpPost.releaseConnection();
}
}
}

View File

@ -1,47 +0,0 @@
package cn.binarywang.wx.miniapp.executor;
import java.io.File;
import java.io.IOException;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.ResponseHandler;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxErrorException;
import cn.binarywang.wx.miniapp.bean.WxMaAuditMediaUploadResult;
/**
* 小程序 提审素材上传接口
* 上传媒体文件请求执行器.
* 请求的参数是File, 返回的结果是String
*
* @author yangyh22
* @since 2020/11/14
*/
public abstract class AuditMediaUploadRequestExecutor<H, P> implements RequestExecutor<WxMaAuditMediaUploadResult, File> {
protected RequestHttp<H, P> requestHttp;
public AuditMediaUploadRequestExecutor(RequestHttp requestHttp) {
this.requestHttp = requestHttp;
}
@Override
public void execute(String uri, File data, ResponseHandler<WxMaAuditMediaUploadResult> handler, WxType wxType) throws WxErrorException, IOException {
handler.handle(this.execute(uri, data, wxType));
}
public static RequestExecutor<WxMaAuditMediaUploadResult, File> create(RequestHttp requestHttp) {
switch (requestHttp.getRequestType()) {
case APACHE_HTTP:
return new ApacheAuditMediaUploadRequestExecutor(requestHttp);
case JODD_HTTP:
return new JoddHttpAuditMediaUploadRequestExecutor(requestHttp);
case OK_HTTP:
return new OkHttpAuditMediaUploadRequestExecutor(requestHttp);
default:
return null;
}
}
}

View File

@ -1,45 +0,0 @@
package cn.binarywang.wx.miniapp.executor;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import jodd.http.HttpConnectionProvider;
import jodd.http.HttpRequest;
import jodd.http.HttpResponse;
import jodd.http.ProxyInfo;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.RequestHttp;
import cn.binarywang.wx.miniapp.bean.WxMaAuditMediaUploadResult;
/**
* @author yangyh22
* @since 2020/11/14
*/
public class JoddHttpAuditMediaUploadRequestExecutor extends AuditMediaUploadRequestExecutor<HttpConnectionProvider, ProxyInfo> {
public JoddHttpAuditMediaUploadRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
@Override
public WxMaAuditMediaUploadResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
HttpRequest request = HttpRequest.post(uri);
if (requestHttp.getRequestHttpProxy() != null) {
requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy());
}
request.withConnectionProvider(requestHttp.getRequestHttpClient());
request.form("media", file);
HttpResponse response = request.send();
response.charset(StandardCharsets.UTF_8.name());
String responseContent = response.bodyText();
WxError error = WxError.fromJson(responseContent, wxType);
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
}
return WxMaAuditMediaUploadResult.fromJson(responseContent);
}
}

View File

@ -1,49 +0,0 @@
package cn.binarywang.wx.miniapp.executor;
import java.io.File;
import java.io.IOException;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.RequestHttp;
import cn.binarywang.wx.miniapp.bean.WxMaAuditMediaUploadResult;
import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* @author yangyh22
* @since 2020/11/14
*/
public class OkHttpAuditMediaUploadRequestExecutor extends AuditMediaUploadRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
public OkHttpAuditMediaUploadRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
@Override
public WxMaAuditMediaUploadResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
RequestBody body = new MultipartBody.Builder()
.setType(MediaType.parse("multipart/form-data"))
.addFormDataPart("media",
file.getName(),
RequestBody.create(MediaType.parse("application/octet-stream"), file))
.build();
Request request = new Request.Builder().url(uri).post(body).build();
Response response = requestHttp.getRequestHttpClient().newCall(request).execute();
String responseContent = response.body().string();
WxError error = WxError.fromJson(responseContent, wxType);
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
}
return WxMaAuditMediaUploadResult.fromJson(responseContent);
}
}

View File

@ -30,7 +30,8 @@ public class WxMaLiveGoodsServiceImplTest {
@Test
public void addGoods() throws Exception {
//上传临时素材
WxMediaUploadResult mediaUpload = this.wxService.getMediaService().uploadMedia("image", new File("E:\\1.png"));
WxMediaUploadResult mediaUpload = this.wxService.getMediaService()
.uploadMedia("image", new File("./static/temp.jpg"));
WxMaLiveGoodInfo goods = new WxMaLiveGoodInfo();
goods.setCoverImgUrl(mediaUpload.getMediaId());

View File

@ -5,6 +5,8 @@ import cn.binarywang.wx.miniapp.config.WxMaConfig;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import cn.binarywang.wx.miniapp.test.ApiTestModule;
import com.google.inject.Inject;
import lombok.SneakyThrows;
import me.chanjar.weixin.common.bean.CommonUploadParam;
import me.chanjar.weixin.common.bean.WxAccessTokenEntity;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
@ -16,6 +18,7 @@ import org.testng.Assert;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;
@ -184,6 +187,14 @@ public class WxMaServiceImplTest {
}
}
@SneakyThrows
@Test
public void upload() {
CommonUploadParam param = CommonUploadParam.fromFile("media", new File("./static/1.jpg"));
String result = wxService.upload("https://api.weixin.qq.com/wxa/sec/uploadauthmaterial", param);
System.out.println(result);
}
@Test
public void testGetWxMaConfig() {
}

View File

@ -8,15 +8,13 @@ import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.ToJson;
import me.chanjar.weixin.common.bean.WxAccessToken;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.bean.WxNetCheckResult;
import me.chanjar.weixin.common.bean.*;
import me.chanjar.weixin.common.enums.TicketType;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.error.WxRuntimeException;
import me.chanjar.weixin.common.executor.CommonUploadRequestExecutor;
import me.chanjar.weixin.common.service.WxImgProcService;
import me.chanjar.weixin.common.service.WxOAuth2Service;
import me.chanjar.weixin.common.service.WxOcrService;
@ -401,6 +399,12 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH
return this.post(url, obj.toJson());
}
@Override
public String upload(String url, CommonUploadParam param) throws WxErrorException {
RequestExecutor<String, CommonUploadParam> executor = CommonUploadRequestExecutor.create(getRequestHttp());
return this.execute(executor, url, param);
}
@Override
public String post(String url, JsonObject jsonObject) throws WxErrorException {
return this.post(url, jsonObject.toString());
@ -543,7 +547,7 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH
@Override
public void setMultiConfigStorages(Map<String, WxMpConfigStorage> configStorages, String defaultMpId) {
// 防止覆盖配置
if(this.configStorageMap != null) {
if (this.configStorageMap != null) {
this.configStorageMap.putAll(configStorages);
} else {
this.configStorageMap = Maps.newHashMap(configStorages);

View File

@ -0,0 +1,82 @@
package me.chanjar.weixin.open.api;
import me.chanjar.weixin.common.bean.CommonUploadData;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.open.bean.auth.*;
/**
* 微信第三方平台 小程序认证接口 (年审)
* https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/product/weapp_wxverify.html
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
public interface WxOpenMaAuthService {
/**
* 1 小程程序认证
*/
String OPEN_MA_AUTH_SUBMIT = "https://api.weixin.qq.com/wxa/sec/wxaauth";
/**
* 2 小程程序认证任务进度查询.
*/
String OPEN_MA_AUTH_QUERY = "https://api.weixin.qq.com/wxa/sec/queryauth";
/**
* 3 小程序认证上传补充材料.
*/
String OPEN_MA_AUTH_UPLOAD = "https://api.weixin.qq.com/wxa/sec/uploadauthmaterial";
/**
* 4 小程序认证重新提审.
*/
String OPEN_MA_AUTH_RESUBMIT = "https://api.weixin.qq.com/wxa/sec/reauth";
/**
* 5 查询个人认证身份选项列表.
*/
String OPEN_MA_AUTH_IDENTITY = "https://api.weixin.qq.com/wxa/sec/authidentitytree";
/**
* 小程序认证提审
*
* @param param 参数
* @return 提交结果须保存任务ID 授权链接
*/
MaAuthSubmitResult submit(MaAuthSubmitParam param) throws WxErrorException;
/**
* 进度查询
*
* @param taskId 任务ID提交任务时返回
*/
MaAuthQueryResult query(String taskId) throws WxErrorException;
/**
* 上传补充材料
*
* @param data 上传数据仅支持png\jpeg\jpg\gif格式文件后缀名如果填写不对会导致上传失败建议写死1.jpg
*/
MaAuthUploadResult upload(CommonUploadData data) throws WxErrorException;
/**
* 重新提审
*
* @param param 参数
* @return 提交结果
*/
MaAuthSubmitResult resubmit(MaAuthResubmitParam param) throws WxErrorException;
/**
* 查询个人认证身份选项列表
*
* @return 职业身份认证树
*/
MaAuthQueryIdentityTreeResult queryIdentityTree() throws WxErrorException;
}

View File

@ -702,6 +702,13 @@ public interface WxOpenMaService extends WxMaService {
*/
WxOpenMaBasicService getBasicService();
/**
* 小程序认证年审服务
*
* @return 小程序认证年审服务
*/
WxOpenMaAuthService getAuthService();
/**
* 小程序用户隐私保护指引服务
*
@ -719,7 +726,7 @@ public interface WxOpenMaService extends WxMaService {
/**
* 小程序审核 提审素材上传接口
*
* @return
* @return 结果
*/
WxMaAuditMediaUploadResult uploadMedia(File file) throws WxErrorException;

View File

@ -0,0 +1,56 @@
package me.chanjar.weixin.open.api.impl;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
import kotlin.Pair;
import kotlin.collections.MapsKt;
import me.chanjar.weixin.common.bean.CommonUploadData;
import me.chanjar.weixin.common.bean.CommonUploadParam;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.open.api.WxOpenMaAuthService;
import me.chanjar.weixin.open.bean.auth.*;
/**
* 微信第三方平台 小程序认证接口 (年审)
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* Created on 2024/01/11
*/
public class WxOpenMaAuthServiceImpl implements WxOpenMaAuthService {
private final WxMaService wxMaService;
public WxOpenMaAuthServiceImpl(WxMaService wxMaService) {
this.wxMaService = wxMaService;
}
@Override
public MaAuthSubmitResult submit(MaAuthSubmitParam param) throws WxErrorException {
String response = wxMaService.post(OPEN_MA_AUTH_SUBMIT, param);
return WxMaGsonBuilder.create().fromJson(response, MaAuthSubmitResult.class);
}
@Override
public MaAuthQueryResult query(String taskId) throws WxErrorException {
String response = wxMaService.post(OPEN_MA_AUTH_QUERY, MapsKt.mapOf(new Pair<>("taskid", taskId)));
return WxMaGsonBuilder.create().fromJson(response, MaAuthQueryResult.class);
}
@Override
public MaAuthUploadResult upload(CommonUploadData data) throws WxErrorException {
String response = wxMaService.upload(OPEN_MA_AUTH_UPLOAD, new CommonUploadParam("media", data));
return WxMaGsonBuilder.create().fromJson(response, MaAuthUploadResult.class);
}
@Override
public MaAuthSubmitResult resubmit(MaAuthResubmitParam param) throws WxErrorException {
String response = wxMaService.post(OPEN_MA_AUTH_RESUBMIT, param);
return WxMaGsonBuilder.create().fromJson(response, MaAuthSubmitResult.class);
}
@Override
public MaAuthQueryIdentityTreeResult queryIdentityTree() throws WxErrorException {
String response = wxMaService.get(OPEN_MA_AUTH_IDENTITY, null);
return WxMaGsonBuilder.create().fromJson(response, MaAuthQueryIdentityTreeResult.class);
}
}

View File

@ -14,6 +14,7 @@ import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import lombok.Getter;
import me.chanjar.weixin.common.bean.CommonUploadParam;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.open.api.*;
import me.chanjar.weixin.open.bean.ma.WxMaPrefetchDomain;
@ -47,6 +48,8 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
@Getter
private final WxOpenMaBasicService basicService;
@Getter
private final WxOpenMaAuthService authService;
@Getter
private final WxOpenMaPrivacyService privacyService;
@Getter
private final WxOpenMaShoppingOrdersService shoppingOrdersService;
@ -56,6 +59,7 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
this.appId = appId;
this.wxMaConfig = wxMaConfig;
this.basicService = new WxOpenMaBasicServiceImpl(this);
this.authService = new WxOpenMaAuthServiceImpl(this);
this.privacyService = new WxOpenMaPrivacyServiceImpl(this);
this.shoppingOrdersService = new WxOpenMaShoppingOrdersServiceImpl(this);
initHttp();
@ -429,7 +433,9 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
@Override
public WxMaAuditMediaUploadResult uploadMedia(File file) throws WxErrorException {
return (WxMaAuditMediaUploadResult) this.execute(AuditMediaUploadRequestExecutor.create(getRequestHttp()), API_AUDIT_UPLOAD_MEDIA, file);
CommonUploadParam param = CommonUploadParam.fromFile("media", file);
String result = upload(API_AUDIT_UPLOAD_MEDIA, param);
return WxMaAuditMediaUploadResult.fromJson(result);
}
private JsonArray toJsonArray(List<String> strList) {

View File

@ -0,0 +1,29 @@
package me.chanjar.weixin.open.bean.auth;
import com.google.gson.annotations.SerializedName;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import me.chanjar.weixin.open.bean.result.WxOpenResult;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* 小程序认证 查询个人认证身份选项列表 响应
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
@Getter
@Setter
@NoArgsConstructor
public class MaAuthQueryIdentityTreeResult extends WxOpenResult {
/**
* 子节点信息 非叶子节点必有
*/
@Nullable
@SerializedName("node_list")
private List<MaAuthQueryIdentityTreeResultIdentityNode> nodeList;
}

View File

@ -0,0 +1,20 @@
package me.chanjar.weixin.open.bean.auth;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 职业身份叶子信息
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
@Data
@NoArgsConstructor
public class MaAuthQueryIdentityTreeResultIdentityLeaf {
/**
* 要求说明
*/
private String requirement;
}

View File

@ -0,0 +1,47 @@
package me.chanjar.weixin.open.bean.auth;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* 职业身份 节点信息
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
@Data
@NoArgsConstructor
public class MaAuthQueryIdentityTreeResultIdentityNode {
/**
* 职业身份名
*/
@NotNull
private String name;
/**
* 职业身份节点ID
*/
@NotNull
@SerializedName("node_id")
private Integer nodeId;
/**
* 要求信息 叶子节点特有
*/
@Nullable
@SerializedName("leaf_info")
private MaAuthQueryIdentityTreeResultIdentityLeaf leafInfo;
/**
* 子节点信息 非叶子节点必有
*/
@Nullable
@SerializedName("node_list")
private List<MaAuthQueryIdentityTreeResultIdentityNode> nodeList;
}

View File

@ -0,0 +1,64 @@
package me.chanjar.weixin.open.bean.auth;
import com.google.gson.annotations.SerializedName;
import lombok.Getter;
import lombok.Setter;
import me.chanjar.weixin.open.bean.result.WxOpenResult;
import org.jetbrains.annotations.NotNull;
/**
* 小程序认证 查询操作 响应
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
@Getter
@Setter
public class MaAuthQueryResult extends WxOpenResult {
/**
* 小程序ID
*/
@NotNull
@SerializedName("appid")
private String appId;
/**
* 状态 0初始 1超24小时 2用户拒绝 3用户同意 4发起人脸 5人脸失败 6人脸ok 7人脸认证后手机验证码 8手机验证失败 9手机验证成功 11创建审核单失败 12创建审核单成功 14验证失败 15等待支付
*/
@NotNull
@SerializedName("task_status")
private Integer taskStatus;
/**
* 授权链接
*/
@NotNull
@SerializedName("auth_url")
private String authUrl;
/**
* 审核单状态创建审核单成功后有效 0审核单不存在 1待支付 2审核中 3打回重填 4认证通过 5认证最终失败不能再修改
*/
@SerializedName("apply_status")
private Integer applyStatus;
/**
* 小程序后台展示的认证订单号
*/
@SerializedName("orderid")
private String orderId;
/**
* 当审核单被打回重填(apply_status=3)时有效
*/
@SerializedName("refill_reason")
private String refillReason;
/**
* 审核最终失败的原因(apply_status=5)时有效
*/
@SerializedName("fail_reason")
private String failReason;
}

View File

@ -0,0 +1,36 @@
package me.chanjar.weixin.open.bean.auth;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.jetbrains.annotations.NotNull;
/**
* 小程序认证 查询操作 响应数据
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
@Data
@NoArgsConstructor
public class MaAuthQueryResultDispatchInfo {
/**
* 提供商上海倍通企业信用征信有限公司
*/
@NotNull
private String provider;
/**
* 联系方式咨询电话0411-84947888咨询时间周一至周五工作日830-1730
*/
@NotNull
private String contact;
/**
* 派遣时间戳()1704952913
*/
@NotNull
@SerializedName("dispatch_time")
private Integer dispatchTime;
}

View File

@ -0,0 +1,22 @@
package me.chanjar.weixin.open.bean.auth;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import org.jetbrains.annotations.NotNull;
/**
* 小程序认证 重新提交操作 参数
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
@Data
public class MaAuthResubmitParam {
/**
* 认证信息
*/
@NotNull
@SerializedName("auth_data")
private MaAuthResubmitParamAuthData authData;
}

View File

@ -0,0 +1,24 @@
package me.chanjar.weixin.open.bean.auth;
import com.google.gson.annotations.SerializedName;
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
/**
* 小程序认证 重新提交操作 认证参数
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
@Getter
@Setter
public class MaAuthResubmitParamAuthData extends MaAuthSubmitParamAuthData {
/**
* 认证任务id
*/
@NotNull
@SerializedName("taskid")
private String taskId;
}

View File

@ -0,0 +1,27 @@
package me.chanjar.weixin.open.bean.auth;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.jetbrains.annotations.NotNull;
/**
* 小程序认证 提交操作 参数
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
@Data
@NoArgsConstructor
public class MaAuthSubmitParam {
/**
* 认证信息
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
@NotNull
@SerializedName("auth_data")
private MaAuthSubmitParamAuthData authData;
}

View File

@ -0,0 +1,110 @@
package me.chanjar.weixin.open.bean.auth;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.lang.Nullable;
import java.util.List;
/**
* 小程序认证 提交操作 参数 数据
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
@Data
@NoArgsConstructor
public class MaAuthSubmitParamAuthData {
/**
* 1企业 12个体户 15个人 参考:https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/basic-info-management/getAccountBasicInfo.html#realname-status-%E5%AE%9E%E5%90%8D%E8%AE%A4%E8%AF%81%E7%8A%B6%E6%80%81%E6%9E%9A%E4%B8%BE%E5%80%BC
*/
@NotNull
@SerializedName("customer_type")
private String customerType;
/**
* 联系人信息
*/
@NotNull
@SerializedName("contact_info")
private MaAuthSubmitParamContactInfo contactInfo;
/**
* 发票信息如果是服务商代缴模式不需要改参数
*/
@Nullable
@SerializedName("invoice_info")
private MaAuthSubmitParamInvoiceInfo invoiceInfo;
/**
* 非个人类型必填主体资质材料 media_id 支持jpg,jpeg .bmp.gif .png格式仅支持一张图片
*/
@Nullable
private String qualification;
/**
* 主体资质其他证明材料 media_id 支持jpg,jpeg .bmp.gif .png格式最多上传10张图片
*/
@Nullable
@SerializedName("qualification_other")
private List<String> qualificationOther;
/**
* 小程序账号名称
*/
@NotNull
@SerializedName("account_name")
private String accountName;
/**
* 小程序账号名称命名类型 1基于自选词汇命名 2基于商标命名
*/
@NotNull
@SerializedName("account_name_type")
private Integer accountNameType;
/**
* 名称命中关键词-补充材料 media_id 支持jpg,jpeg .bmp.gif .png格式支持上传多张图片
*/
@Nullable
@SerializedName("account_supplemental")
private List<String> accountSupplemental;
/**
* 支付方式 1消耗服务商预购包 2小程序开发者自行支付
*/
@NotNull
@SerializedName("pay_type")
private String payType;
/**
* 认证类型为个人类型时可以选择要认证的身份/wxa/sec/authidentitytree 里获取填叶节点的name
*/
@Nullable
@SerializedName("auth_identification")
private String authIdentification;
/**
* 填了auth_identification则必填身份证明材料 media_id 1基于不同认证身份上传不同的材料2认证类型=1时选填支持上传10张图片3支持jpg,jpeg .bmp.gif .png格式
*/
@Nullable
@SerializedName("auth_ident_material")
private String authIdentMaterial;
/**
* 第三方联系电话
*/
@NotNull
@SerializedName("third_party_phone")
private String thirdPartyPhone;
/**
* 选择服务商代缴模式时必填服务市场appid
*/
@Nullable
@SerializedName("service_appid")
private String serviceAppid;
}

View File

@ -0,0 +1,28 @@
package me.chanjar.weixin.open.bean.auth;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.jetbrains.annotations.NotNull;
/**
* 联系人信息
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
@Data
@NoArgsConstructor
public class MaAuthSubmitParamContactInfo {
/**
* 姓名
*/
@NotNull
private String name;
/**
* 邮箱
*/
@NotNull
private String email;
}

View File

@ -0,0 +1,29 @@
package me.chanjar.weixin.open.bean.auth;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.lang.Nullable;
/**
* 发票 - 电子发票
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
@Data
@NoArgsConstructor
public class MaAuthSubmitParamInvoiceElectronic {
/**
* 纳税识别号15位1718或20位
*/
@NotNull
private String id;
/**
* 发票备注选填
*/
@Nullable
private String desc;
}

View File

@ -0,0 +1,44 @@
package me.chanjar.weixin.open.bean.auth;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.lang.Nullable;
/**
* 发票信息
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
@Data
@NoArgsConstructor
public class MaAuthSubmitParamInvoiceInfo {
/**
* 发票类型 1: 不开发票 2: 电子发票 3: 增值税专票
*/
@NotNull
@SerializedName("invoice_type")
private Integer invoiceType;
/**
* 发票类型=2时必填 电子发票开票信息
*/
@Nullable
private MaAuthSubmitParamInvoiceElectronic electronic;
/**
* 发票类型=3时必填 增值税专票开票信息
*/
@Nullable
private MaAuthSubmitParamInvoiceVat vat;
/**
* 发票抬头发票类型!=1时必填 需要和认证主体名称一样
*/
@Nullable
@SerializedName("invoice_title")
private String invoiceTitle;
}

View File

@ -0,0 +1,102 @@
package me.chanjar.weixin.open.bean.auth;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.lang.Nullable;
/**
* 发票 - 增值税专票
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
@Data
@NoArgsConstructor
public class MaAuthSubmitParamInvoiceVat {
/**
* 企业电话
*/
@NotNull
@SerializedName("enterprise_phone")
private String enterprisePhone;
/**
* 纳税识别号15位1718或20位
*/
@NotNull
private String id;
/**
* 企业注册地址
*/
@NotNull
@SerializedName("enterprise_address")
private String enterpriseAddress;
/**
* 企业开户银行
*/
@NotNull
@SerializedName("bank_name")
private String bankName;
/**
* 企业银行账号
*/
@NotNull
@SerializedName("bank_account")
private String bankAccount;
/**
* 发票邮寄地址邮编
*/
@NotNull
@SerializedName("mailing_address")
private String mailingAddress;
/**
* 街道地址
*/
@NotNull
private String address;
/**
* 联系人
*/
@NotNull
private String name;
/**
* 联系电话
*/
@NotNull
private String phone;
/**
* 省份
*/
@NotNull
private String province;
/**
* 城市
*/
@NotNull
private String city;
/**
* 县区
*/
@NotNull
private String district;
/**
* 发票备注选填
*/
@Nullable
private String desc;
}

View File

@ -0,0 +1,34 @@
package me.chanjar.weixin.open.bean.auth;
import com.google.gson.annotations.SerializedName;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import me.chanjar.weixin.open.bean.result.WxOpenResult;
import org.jetbrains.annotations.NotNull;
/**
* 小程序认证 提交操作 响应
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
@Getter
@Setter
@NoArgsConstructor
public class MaAuthSubmitResult extends WxOpenResult {
/**
* 任务ID
*/
@NotNull
@SerializedName("taskid")
private String taskId;
/**
* 小程序管理员授权链接
*/
@NotNull
@SerializedName("auth_url")
private String authUrl;
}

View File

@ -0,0 +1,27 @@
package me.chanjar.weixin.open.bean.auth;
import com.google.gson.annotations.SerializedName;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import me.chanjar.weixin.open.bean.result.WxOpenResult;
import org.jetbrains.annotations.NotNull;
/**
* 小程序认证 上传补充材料操作 响应
*
* @author <a href="https://www.sacoc.cn">广州跨界</a>
* created on 2024/01/11
*/
@Getter
@Setter
@NoArgsConstructor
public class MaAuthUploadResult extends WxOpenResult {
/**
* 媒体ID
*/
@NotNull
@SerializedName("mediaid")
private String mediaId;
}

View File

@ -1,44 +1,23 @@
package me.chanjar.weixin.qidian.api.impl;
import static me.chanjar.weixin.qidian.enums.WxQidianApiUrl.Other.CLEAR_QUOTA_URL;
import static me.chanjar.weixin.qidian.enums.WxQidianApiUrl.Other.GET_CALLBACK_IP_URL;
import static me.chanjar.weixin.qidian.enums.WxQidianApiUrl.Other.GET_CURRENT_AUTOREPLY_INFO_URL;
import static me.chanjar.weixin.qidian.enums.WxQidianApiUrl.Other.GET_TICKET_URL;
import static me.chanjar.weixin.qidian.enums.WxQidianApiUrl.Other.NETCHECK_URL;
import static me.chanjar.weixin.qidian.enums.WxQidianApiUrl.Other.QRCONNECT_URL;
import static me.chanjar.weixin.qidian.enums.WxQidianApiUrl.Other.SHORTURL_API_URL;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import org.apache.commons.lang3.StringUtils;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.ToJson;
import me.chanjar.weixin.common.bean.WxAccessToken;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.bean.WxNetCheckResult;
import me.chanjar.weixin.common.bean.*;
import me.chanjar.weixin.common.enums.TicketType;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.error.WxRuntimeException;
import me.chanjar.weixin.common.executor.CommonUploadRequestExecutor;
import me.chanjar.weixin.common.util.DataUtils;
import me.chanjar.weixin.common.util.RandomUtils;
import me.chanjar.weixin.common.util.crypto.SHA1;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
import me.chanjar.weixin.common.util.http.URIUtil;
import me.chanjar.weixin.common.util.http.*;
import me.chanjar.weixin.common.util.json.GsonParser;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import me.chanjar.weixin.qidian.api.WxQidianCallDataService;
@ -47,6 +26,13 @@ import me.chanjar.weixin.qidian.api.WxQidianService;
import me.chanjar.weixin.qidian.config.WxQidianConfigStorage;
import me.chanjar.weixin.qidian.enums.WxQidianApiUrl;
import me.chanjar.weixin.qidian.util.WxQidianConfigStorageHolder;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import static me.chanjar.weixin.qidian.enums.WxQidianApiUrl.Other.*;
/**
* 基础实现类.
@ -56,9 +42,9 @@ import me.chanjar.weixin.qidian.util.WxQidianConfigStorageHolder;
@Slf4j
public abstract class BaseWxQidianServiceImpl<H, P> implements WxQidianService, RequestHttp<H, P> {
@Getter
private WxQidianDialService dialService = new WxQidianDialServiceImpl(this);
private final WxQidianDialService dialService = new WxQidianDialServiceImpl(this);
@Getter
private WxQidianCallDataService callDataService = new WxQidianCallDataServiceImpl(this);
private final WxQidianCallDataService callDataService = new WxQidianCallDataServiceImpl(this);
private Map<String, WxQidianConfigStorage> configStorageMap;
@ -93,7 +79,7 @@ public abstract class BaseWxQidianServiceImpl<H, P> implements WxQidianService,
try {
if (this.getWxMpConfigStorage().isTicketExpired(type)) {
String responseContent = execute(SimpleGetRequestExecutor.create(this),
GET_TICKET_URL.getUrl(this.getWxMpConfigStorage()) + type.getCode(), null);
GET_TICKET_URL.getUrl(this.getWxMpConfigStorage()) + type.getCode(), null);
JsonObject tmpJsonObject = GsonParser.parse(responseContent);
String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
@ -123,7 +109,7 @@ public abstract class BaseWxQidianServiceImpl<H, P> implements WxQidianService,
String randomStr = RandomUtils.getRandomStr();
String jsapiTicket = getJsapiTicket(false);
String signature = SHA1.genWithAmple("jsapi_ticket=" + jsapiTicket, "noncestr=" + randomStr,
"timestamp=" + timestamp, "url=" + url);
"timestamp=" + timestamp, "url=" + url);
WxJsapiSignature jsapiSignature = new WxJsapiSignature();
jsapiSignature.setAppId(this.getWxMpConfigStorage().getAppId());
jsapiSignature.setTimestamp(timestamp);
@ -154,7 +140,7 @@ public abstract class BaseWxQidianServiceImpl<H, P> implements WxQidianService,
@Override
public String buildQrConnectUrl(String redirectUri, String scope, String state) {
return String.format(QRCONNECT_URL.getUrl(this.getWxMpConfigStorage()), this.getWxMpConfigStorage().getAppId(),
URIUtil.encodeURIComponent(redirectUri), scope, StringUtils.trimToEmpty(state));
URIUtil.encodeURIComponent(redirectUri), scope, StringUtils.trimToEmpty(state));
}
@Override
@ -215,6 +201,12 @@ public abstract class BaseWxQidianServiceImpl<H, P> implements WxQidianService,
return this.post(url, obj.toJson());
}
@Override
public String upload(String url, CommonUploadParam param) throws WxErrorException {
RequestExecutor<String, CommonUploadParam> executor = CommonUploadRequestExecutor.create(getRequestHttp());
return this.execute(executor, url, param);
}
@Override
public String post(String url, JsonObject jsonObject) throws WxErrorException {
return this.post(url, jsonObject.toString());