Skip to content

Commit ef99e3d

Browse files
authoredNov 14, 2021
🆕 #2385 【开放平台】 增加为小程序设置用户隐私指引的相关接口
1 parent 23a115f commit ef99e3d

File tree

11 files changed

+657
-0
lines changed

11 files changed

+657
-0
lines changed
 

‎weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxError.java

+7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import lombok.Builder;
44
import lombok.Data;
5+
import lombok.NoArgsConstructor;
56
import me.chanjar.weixin.common.enums.WxType;
67
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
78
import org.apache.commons.lang3.StringUtils;
@@ -17,6 +18,7 @@
1718
* @author Daniel Qian & Binary Wang
1819
*/
1920
@Data
21+
@NoArgsConstructor
2022
@Builder
2123
public class WxError implements Serializable {
2224
private static final long serialVersionUID = 7869786563361406291L;
@@ -39,6 +41,11 @@ public class WxError implements Serializable {
3941

4042
private String json;
4143

44+
public WxError(int errorCode, String errorMsg) {
45+
this.errorCode = errorCode;
46+
this.errorMsg = errorMsg;
47+
}
48+
4249
public static WxError fromJson(String json) {
4350
return fromJson(json, null);
4451
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package me.chanjar.weixin.open.api;
2+
3+
import me.chanjar.weixin.common.error.WxErrorException;
4+
import me.chanjar.weixin.open.bean.ma.privacy.GetPrivacySettingResult;
5+
import me.chanjar.weixin.open.bean.ma.privacy.SetPrivacySetting;
6+
import me.chanjar.weixin.open.bean.ma.privacy.UploadPrivacyFileResult;
7+
import org.jetbrains.annotations.Nullable;
8+
9+
/**
10+
* 微信第三方平台 小程序用户隐私保护指引接口
11+
* https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/api/privacy_config/set_privacy_setting.html
12+
*
13+
* @author <a href="https://www.sacoc.cn">广州跨界</a>
14+
*/
15+
public interface WxOpenMaPrivacyService {
16+
17+
/**
18+
* 1 设置小程序用户隐私保护指引
19+
*/
20+
String OPEN_SET_PRIVACY_SETTING = "https://api.weixin.qq.com/cgi-bin/component/setprivacysetting";
21+
22+
/**
23+
* 2 查询小程序用户隐私保护指引
24+
*/
25+
String OPEN_GET_PRIVACY_SETTING = "https://api.weixin.qq.com/cgi-bin/component/getprivacysetting";
26+
27+
/**
28+
* 3 上传小程序用户隐私保护指引文件
29+
*/
30+
String OPEN_UPLOAD_PRIVACY_FILE = "https://api.weixin.qq.com/cgi-bin/component/uploadprivacyextfile";
31+
32+
33+
/**
34+
* 查询小程序用户隐私保护指引
35+
* 文档地址:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/api/privacy_config/get_privacy_setting.html
36+
*
37+
* @param privacyVer 1表示现网版本,即,传1则该接口返回的内容是现网版本的;2表示开发版,即,传2则该接口返回的内容是开发版本的。默认是2。
38+
* @return 查询结果
39+
* @throws WxErrorException 如果出错,抛出此异常
40+
*/
41+
GetPrivacySettingResult getPrivacySetting(@Nullable Integer privacyVer) throws WxErrorException;
42+
43+
44+
/**
45+
* 设置小程序用户隐私保护指引
46+
* 文档地址:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/api/privacy_config/set_privacy_setting.html
47+
*
48+
* @param dto 参数对象
49+
* @throws WxErrorException 如果出错,抛出此异常
50+
*/
51+
void setPrivacySetting(SetPrivacySetting dto) throws WxErrorException;
52+
53+
54+
/**
55+
* 上传小程序用户隐私保护指引文件
56+
* 本接口用于上传自定义的小程序的用户隐私保护指引
57+
* 仅限文本文件, 限制文件大小为不超过100kb,否则会报错
58+
* 文档地址:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/api/privacy_config/upload_privacy_exfile.html
59+
*
60+
* @param content 文本文件内容
61+
* @return 上传结果
62+
* @throws WxErrorException 如果出错,抛出此异常
63+
*/
64+
UploadPrivacyFileResult uploadPrivacyFile(String content) throws WxErrorException;
65+
}

‎weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java

+7
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,13 @@ WxOpenMaDomainResult modifyDomain(String action, List<String> requestDomains, Li
632632
*/
633633
WxOpenMaBasicService getBasicService();
634634

635+
/**
636+
* 小程序用户隐私保护指引服务
637+
*
638+
* @return 小程序用户隐私保护指引服务
639+
*/
640+
WxOpenMaPrivacyService getPrivacyService();
641+
635642
/**
636643
* 小程序审核 提审素材上传接口
637644
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package me.chanjar.weixin.open.api.impl;
2+
3+
import cn.binarywang.wx.miniapp.api.WxMaService;
4+
import lombok.AllArgsConstructor;
5+
import lombok.SneakyThrows;
6+
import me.chanjar.weixin.common.error.WxError;
7+
import me.chanjar.weixin.common.error.WxErrorException;
8+
import me.chanjar.weixin.open.api.WxOpenMaPrivacyService;
9+
import me.chanjar.weixin.open.bean.ma.privacy.GetPrivacySettingResult;
10+
import me.chanjar.weixin.open.bean.ma.privacy.SetPrivacySetting;
11+
import me.chanjar.weixin.open.bean.ma.privacy.UploadPrivacyFileResult;
12+
import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder;
13+
import org.jetbrains.annotations.Nullable;
14+
15+
import java.util.HashMap;
16+
import java.util.Map;
17+
18+
/**
19+
* 微信第三方平台 小程序用户隐私保护指引接口
20+
* https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/api/privacy_config/set_privacy_setting.html
21+
*
22+
* @author <a href="https://www.sacoc.cn">广州跨界</a>
23+
*/
24+
@AllArgsConstructor
25+
public class WxOpenMaPrivacyServiceImpl implements WxOpenMaPrivacyService {
26+
27+
private final WxMaService wxMaService;
28+
29+
30+
@Override
31+
public GetPrivacySettingResult getPrivacySetting(@Nullable Integer privacyVer) throws WxErrorException {
32+
Map<String, Object> params = new HashMap<>();
33+
if (privacyVer != null) {
34+
params.put("privacy_ver", privacyVer);
35+
}
36+
String json = wxMaService.post(OPEN_GET_PRIVACY_SETTING, params);
37+
return WxOpenGsonBuilder.create().fromJson(json, GetPrivacySettingResult.class);
38+
}
39+
40+
@Override
41+
public void setPrivacySetting(SetPrivacySetting dto) throws WxErrorException {
42+
wxMaService.post(OPEN_SET_PRIVACY_SETTING, dto);
43+
}
44+
45+
@SneakyThrows
46+
@Override
47+
public UploadPrivacyFileResult uploadPrivacyFile(String content) throws WxErrorException {
48+
// TODO 应实现通过InputStream上传的功能,一下代码暂时无法正常运行
49+
// ByteArrayInputStream data = new ByteArrayInputStream(content.getBytes("GBK"));
50+
// GenericUploadRequestExecutor executor = new GenericUploadRequestExecutor(wxMaService.getRequestHttp(), "POST", "file", "/temp.txt");
51+
// String json = wxMaService.execute(executor, OPEN_UPLOAD_PRIVACY_FILE, data);
52+
// return WxOpenGsonBuilder.create().fromJson(json, UploadPrivacyFileResult.class);
53+
throw new WxErrorException(new WxError(5003, "暂未实现用户隐私指引内容上传"));
54+
}
55+
}

‎weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import me.chanjar.weixin.common.error.WxErrorException;
1616
import me.chanjar.weixin.open.api.WxOpenComponentService;
1717
import me.chanjar.weixin.open.api.WxOpenMaBasicService;
18+
import me.chanjar.weixin.open.api.WxOpenMaPrivacyService;
1819
import me.chanjar.weixin.open.api.WxOpenMaService;
1920
import me.chanjar.weixin.open.bean.ma.WxMaQrcodeParam;
2021
import me.chanjar.weixin.open.bean.ma.WxMaScheme;
@@ -42,12 +43,15 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
4243
private final String appId;
4344
@Getter
4445
private final WxOpenMaBasicService basicService;
46+
@Getter
47+
private final WxOpenMaPrivacyService privacyService;
4548

4649
public WxOpenMaServiceImpl(WxOpenComponentService wxOpenComponentService, String appId, WxMaConfig wxMaConfig) {
4750
this.wxOpenComponentService = wxOpenComponentService;
4851
this.appId = appId;
4952
this.wxMaConfig = wxMaConfig;
5053
this.basicService = new WxOpenMaBasicServiceImpl(this);
54+
this.privacyService = new WxOpenMaPrivacyServiceImpl(this);
5155
initHttp();
5256
}
5357

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package me.chanjar.weixin.open.bean.ma.privacy;
2+
3+
import com.google.gson.annotations.SerializedName;
4+
import lombok.Data;
5+
import lombok.Getter;
6+
import lombok.Setter;
7+
import me.chanjar.weixin.open.bean.result.WxOpenResult;
8+
9+
import java.util.List;
10+
11+
/**
12+
* 查询小程序用户隐私保护指引 响应
13+
*
14+
* @author <a href="https://www.sacoc.cn">广州跨界</a>
15+
*/
16+
@Getter
17+
@Setter
18+
public class GetPrivacySettingResult extends WxOpenResult {
19+
20+
/**
21+
* 代码是否存在, 0 不存在, 1 存在 。如果最近没有通过commit接口上传代码,则会出现 code_exist=0的情况。
22+
*/
23+
@SerializedName("code_exist")
24+
private Integer codeExist;
25+
26+
/**
27+
* 代码检测出来的用户信息类型(privacy_key)
28+
*/
29+
@SerializedName("privacy_list")
30+
private List<String> privacyList;
31+
32+
/**
33+
* 要收集的用户信息配置
34+
*/
35+
@SerializedName("setting_list")
36+
private List<Setting> settingList;
37+
38+
/**
39+
* 更新时间
40+
*/
41+
@SerializedName("update_time")
42+
private Long updateTime;
43+
44+
/**
45+
* 收集方(开发者)信息配置
46+
*/
47+
@SerializedName("owner_setting")
48+
private PrivacyOwnerSetting ownerSetting;
49+
50+
/**
51+
* 收集方(开发者)信息配置
52+
*/
53+
@SerializedName("privacy_desc")
54+
private PrivacyDesc privacyDesc;
55+
56+
57+
@Data
58+
public static class Setting {
59+
60+
/**
61+
* 官方的可选值参考下方说明;该字段也支持自定义
62+
*
63+
* @see PrivacyKeyEnum
64+
* @see PrivacyKeyEnum#getKey()
65+
*/
66+
@SerializedName("privacy_key")
67+
private String privacyKey;
68+
69+
/**
70+
* 请填写收集该信息的用途。例如privacy_key=Location(位置信息),那么privacy_text则填写收集位置信息的用途。
71+
* 无需再带上“为了”或者“用于”这些字眼,小程序端的显示格式是为了xxx,因此开发者只需要直接填写用途即可。
72+
*/
73+
@SerializedName("privacy_text")
74+
private String privacyText;
75+
76+
/**
77+
* 用户信息类型的中文名称
78+
*
79+
* @see PrivacyKeyEnum#getDesc() ()
80+
*/
81+
@SerializedName("privacy_label")
82+
private String privacyLabel;
83+
}
84+
85+
86+
@Data
87+
public static class PrivacyDesc {
88+
89+
/**
90+
* 用户信息类型
91+
*/
92+
@SerializedName("privacy_desc_list")
93+
private List<PrivacyDescItem> privacyDescList;
94+
}
95+
96+
@Data
97+
public static class PrivacyDescItem {
98+
99+
/**
100+
* 用户信息类型的英文key
101+
*
102+
* @see PrivacyKeyEnum
103+
* @see PrivacyKeyEnum#getKey()
104+
*/
105+
@SerializedName("privacy_key")
106+
private String privacyKey;
107+
108+
/**
109+
* 用户信息类型的中文描述
110+
*
111+
* @see PrivacyKeyEnum#getDesc()
112+
*/
113+
@SerializedName("privacy_desc")
114+
private String privacyDesc;
115+
}
116+
117+
118+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package me.chanjar.weixin.open.bean.ma.privacy;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Getter;
5+
6+
/**
7+
* 隐私key枚举
8+
*
9+
* @author <a href="https://www.sacoc.cn">广州跨界</a>
10+
*/
11+
@Getter
12+
@AllArgsConstructor
13+
public enum PrivacyKeyEnum {
14+
15+
USER_INFO("UserInfo", "用户信息(微信昵称、头像)"),
16+
17+
LOCATION("Location", "位置信息"),
18+
19+
ADDRESS("Address", "地址"),
20+
21+
INVOICE("Invoice", "发票信息"),
22+
23+
RUN_DATA("RunData", "微信运动数据"),
24+
25+
RECORD("Record", "麦克风"),
26+
27+
ALBUM("Album", "选中的照片或视频信息"),
28+
29+
CAMERA("Camera", "摄像头"),
30+
31+
PHONE_NUMBER("PhoneNumber", "手机号码"),
32+
33+
CONTACT("Contact", "通讯录(仅写入)权限"),
34+
35+
DEVICE_INFO("DeviceInfo", "设备信息"),
36+
37+
EXID_NUMBER("EXIDNumber", "身份证号码"),
38+
39+
EX_ORDER_INFO("EXOrderInfo", "订单信息"),
40+
41+
EX_USER_PUBLISH_CONTENT("EXUserPublishContent", "发布内容"),
42+
43+
EX_USER_FOLLOW_ACCT("EXUserFollowAcct", "所关注账号"),
44+
45+
EX_USER_OP_LOG("EXUserOpLog", "操作日志"),
46+
47+
ALBUM_WRITE_ONLY("AlbumWriteOnly", "相册(仅写入)权限"),
48+
49+
LICENSE_PLATE("LicensePlate", "车牌号"),
50+
51+
BLUE_TOOTH("BlueTooth", "蓝牙"),
52+
53+
CALENDAR_WRITE_ONLY("CalendarWriteOnly", "日历(仅写入)权限"),
54+
55+
EMAIL("Email", "邮箱"),
56+
57+
MESSAGE_FILE("MessageFile", "选中的文件"),
58+
;
59+
60+
private final String key;
61+
private final String desc;
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package me.chanjar.weixin.open.bean.ma.privacy;
2+
3+
import com.google.gson.annotations.SerializedName;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
import org.jetbrains.annotations.NotNull;
9+
10+
/**
11+
* 小程序用户隐私保护指引 收集方(开发者)信息配置
12+
*
13+
* @author <a href="https://www.sacoc.cn">广州跨界</a>
14+
*/
15+
@Data
16+
@Builder
17+
@NoArgsConstructor
18+
@AllArgsConstructor
19+
public class PrivacyOwnerSetting {
20+
21+
/**
22+
* 信息收集方(开发者)的邮箱地址,4种联系方式至少要填一种
23+
*/
24+
@SerializedName("contact_email")
25+
private String contactEmail;
26+
27+
/**
28+
* 信息收集方(开发者)的手机号,4种联系方式至少要填一种
29+
*/
30+
@SerializedName("contact_phone")
31+
private String contactPhone;
32+
33+
/**
34+
* 信息收集方(开发者)的qq号,4种联系方式至少要填一种
35+
*/
36+
@SerializedName("contact_qq")
37+
private String contactQq;
38+
39+
/**
40+
* 信息收集方(开发者)的微信号,4种联系方式至少要填一种
41+
*/
42+
@SerializedName("contact_weixin")
43+
private String contactWeixin;
44+
45+
/**
46+
* 如果开发者不使用微信提供的标准化用户隐私保护指引模板,也可以上传自定义的用户隐私保护指引,通过上传接口上传后可获取media_id
47+
*/
48+
@SerializedName("ext_file_media_id")
49+
private String extFileMediaId;
50+
51+
/**
52+
* 通知方式,指的是当开发者收集信息有变动时,通过该方式通知用户。这里服务商需要按照实际情况填写,例如通过弹窗或者公告或者其他方式。
53+
*/
54+
@NotNull
55+
@SerializedName("notice_method")
56+
private String noticeMethod;
57+
58+
/**
59+
* 存储期限,指的是开发者收集用户信息存储多久。如果不填则展示为【开发者承诺,除法律法规另有规定,开发者对你的信息保存期限应当为实现处理目的所必要的最短时间】,
60+
* 如果填请填数字+天,例如“30天”,否则会出现87072的报错。
61+
*/
62+
@SerializedName("store_expire_timestamp")
63+
private String storeExpireTimestamp;
64+
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package me.chanjar.weixin.open.bean.ma.privacy;
2+
3+
import com.google.gson.annotations.SerializedName;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
import org.jetbrains.annotations.NotNull;
9+
10+
import java.util.List;
11+
12+
/**
13+
* 设置小程序用户隐私保护指引参数
14+
*
15+
* @author <a href="https://www.sacoc.cn">广州跨界</a>
16+
*/
17+
@Data
18+
@Builder
19+
@NoArgsConstructor
20+
@AllArgsConstructor
21+
public class SetPrivacySetting {
22+
23+
/**
24+
* 用户隐私保护指引的版本,1表示现网版本;2表示开发版。默认是2开发版。
25+
*/
26+
@SerializedName("privacy_ver")
27+
private Integer privacyVer;
28+
29+
/**
30+
* 收集方(开发者)信息配置
31+
*/
32+
@NotNull
33+
@SerializedName("owner_setting")
34+
private PrivacyOwnerSetting ownerSetting;
35+
36+
/**
37+
* 要收集的用户信息配置
38+
*/
39+
@NotNull
40+
@SerializedName("setting_list")
41+
private List<Setting> settingList;
42+
43+
44+
@Data
45+
@Builder
46+
@NoArgsConstructor
47+
@AllArgsConstructor
48+
public static class Setting {
49+
50+
/**
51+
* 官方的可选值参考下方说明;该字段也支持自定义
52+
*
53+
* @see PrivacyKeyEnum
54+
* @see PrivacyKeyEnum#getKey()
55+
*/
56+
@NotNull
57+
@SerializedName("privacy_key")
58+
private String privacyKey;
59+
60+
/**
61+
* 请填写收集该信息的用途。例如privacy_key=Location(位置信息),那么privacy_text则填写收集位置信息的用途。
62+
* 无需再带上“为了”或者“用于”这些字眼,小程序端的显示格式是为了xxx,因此开发者只需要直接填写用途即可。
63+
*/
64+
@NotNull
65+
@SerializedName("privacy_text")
66+
private String privacyText;
67+
}
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package me.chanjar.weixin.open.bean.ma.privacy;
2+
3+
import com.google.gson.annotations.SerializedName;
4+
import lombok.Getter;
5+
import lombok.Setter;
6+
import me.chanjar.weixin.open.bean.result.WxOpenResult;
7+
8+
/**
9+
* 上传小程序用户隐私保护指引文件 响应
10+
*
11+
* @author <a href="https://www.sacoc.cn">广州跨界</a>
12+
*/
13+
@Getter
14+
@Setter
15+
public class UploadPrivacyFileResult extends WxOpenResult {
16+
17+
/**
18+
* 文件的media_id
19+
*/
20+
@SerializedName("ext_file_media_id")
21+
private String extFileMediaId;
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
package me.chanjar.weixin.open.executor;
2+
3+
import jodd.http.HttpConnectionProvider;
4+
import jodd.http.HttpRequest;
5+
import jodd.http.HttpResponse;
6+
import jodd.http.ProxyInfo;
7+
import lombok.Data;
8+
import me.chanjar.weixin.common.enums.WxType;
9+
import me.chanjar.weixin.common.error.WxError;
10+
import me.chanjar.weixin.common.error.WxErrorException;
11+
import me.chanjar.weixin.common.util.http.RequestExecutor;
12+
import me.chanjar.weixin.common.util.http.RequestHttp;
13+
import me.chanjar.weixin.common.util.http.ResponseHandler;
14+
import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;
15+
import okhttp3.*;
16+
import org.apache.commons.io.IOUtils;
17+
import org.apache.http.HttpEntity;
18+
import org.apache.http.HttpHost;
19+
import org.apache.http.client.config.RequestConfig;
20+
import org.apache.http.client.methods.*;
21+
import org.apache.http.entity.ContentType;
22+
import org.apache.http.entity.mime.HttpMultipartMode;
23+
import org.apache.http.entity.mime.MultipartEntityBuilder;
24+
import org.apache.http.impl.client.CloseableHttpClient;
25+
26+
import java.io.ByteArrayInputStream;
27+
import java.io.IOException;
28+
import java.io.InputStream;
29+
import java.nio.charset.StandardCharsets;
30+
import java.util.Objects;
31+
32+
/**
33+
* 通用的上传请求执行器
34+
*/
35+
public class GenericUploadRequestExecutor implements RequestExecutor<String, InputStream> {
36+
37+
private final Executor<?, ?> executor;
38+
39+
/**
40+
* 构造通用执行器
41+
*
42+
* @param requestHttp http请求
43+
* @param httpMethod http方法(POST PUT PATCH)
44+
* @param paramName 参数名
45+
* @param fileName 文件名
46+
*/
47+
@SuppressWarnings("all")
48+
public GenericUploadRequestExecutor(RequestHttp<?, ?> requestHttp, String httpMethod, String paramName, String fileName) {
49+
switch (requestHttp.getRequestType()) {
50+
case APACHE_HTTP:
51+
executor = new ApacheExecutor();
52+
break;
53+
case OK_HTTP:
54+
executor = new OkExecutor();
55+
break;
56+
case JODD_HTTP:
57+
executor = new JoddExecutor();
58+
break;
59+
default:
60+
throw new UnsupportedOperationException("使用了暂不支持的HTTP客户端:" + requestHttp.getRequestType());
61+
}
62+
executor.setRequestHttp((RequestHttp) requestHttp);
63+
executor.setHttpMethod(httpMethod);
64+
executor.setParamName(paramName);
65+
executor.setFileName(fileName);
66+
}
67+
68+
@Override
69+
public String execute(String uri, InputStream data, WxType wxType) throws WxErrorException, IOException {
70+
String json = executor.execute(uri, data, wxType);
71+
WxError error = WxError.fromJson(json, wxType);
72+
if (error.getErrorCode() != 0) {
73+
throw new WxErrorException(error);
74+
}
75+
return json;
76+
}
77+
78+
@Override
79+
public void execute(String uri, InputStream data, ResponseHandler<String> handler, WxType wxType) throws WxErrorException, IOException {
80+
handler.handle(this.execute(uri, data, wxType));
81+
}
82+
83+
/**
84+
* 内部请求执行器
85+
*
86+
* @param <CLIENT> http客户端
87+
* @param <PROXY> http代理
88+
*/
89+
@Data
90+
public static abstract class Executor<CLIENT, PROXY> {
91+
92+
private RequestHttp<CLIENT, PROXY> requestHttp;
93+
private String httpMethod;
94+
private String paramName;
95+
private String fileName;
96+
97+
public abstract String execute(String uri, InputStream data, WxType wxType) throws WxErrorException, IOException;
98+
}
99+
100+
/**
101+
* 阿帕奇执行器
102+
*/
103+
public static class ApacheExecutor extends Executor<CloseableHttpClient, HttpHost> {
104+
105+
@Override
106+
public String execute(String uri, InputStream data, WxType wxType) throws WxErrorException, IOException {
107+
HttpEntityEnclosingRequestBase bodyRequest;
108+
switch (getHttpMethod()) {
109+
case "POST":
110+
bodyRequest = new HttpPost(uri);
111+
break;
112+
case "PUT":
113+
bodyRequest = new HttpPut(uri);
114+
break;
115+
case "PATCH":
116+
bodyRequest = new HttpPatch(uri);
117+
break;
118+
default:
119+
throw new IllegalAccessError("不支持的请求方式:" + getHttpMethod());
120+
}
121+
if (getRequestHttp().getRequestHttpProxy() != null) {
122+
RequestConfig config = RequestConfig.custom().setProxy(getRequestHttp().getRequestHttpProxy()).build();
123+
bodyRequest.setConfig(config);
124+
}
125+
126+
HttpEntity entity = MultipartEntityBuilder
127+
.create()
128+
.addBinaryBody(getParamName(), data, ContentType.create("multipart/form-data", StandardCharsets.UTF_8), getFileName())
129+
.setMode(HttpMultipartMode.RFC6532)
130+
.build();
131+
bodyRequest.setEntity(entity);
132+
bodyRequest.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString());
133+
134+
try (CloseableHttpResponse response = getRequestHttp().getRequestHttpClient().execute(bodyRequest)) {
135+
return Utf8ResponseHandler.INSTANCE.handleResponse(response);
136+
} finally {
137+
bodyRequest.releaseConnection();
138+
}
139+
}
140+
}
141+
142+
/**
143+
* ok执行器
144+
*/
145+
public static class OkExecutor extends Executor<OkHttpClient, HttpHost> {
146+
147+
@Override
148+
public String execute(String uri, InputStream data, WxType wxType) throws WxErrorException, IOException {
149+
OkHttpClient client = getRequestHttp().getRequestHttpClient();
150+
151+
byte[] bytes = data instanceof ByteArrayInputStream ? ((ByteArrayInputStream) data).readAllBytes() : IOUtils.toByteArray(data);
152+
RequestBody body = new MultipartBody.Builder()
153+
.setType(Objects.requireNonNull(MediaType.parse("multipart/form-data")))
154+
.addFormDataPart("media", getFileName(), RequestBody.create(bytes, MediaType.parse("application/octet-stream")))
155+
.build();
156+
157+
Request request = new Request.Builder().url(uri).method(getHttpMethod(), body).build();
158+
Response response = client.newCall(request).execute();
159+
return response.body().string();
160+
}
161+
}
162+
163+
/**
164+
* jodd执行器
165+
*/
166+
public static class JoddExecutor extends Executor<HttpConnectionProvider, ProxyInfo> {
167+
168+
@Override
169+
public String execute(String uri, InputStream data, WxType wxType) throws WxErrorException, IOException {
170+
HttpRequest request = HttpRequest.post(uri);
171+
if (getRequestHttp().getRequestHttpProxy() != null) {
172+
getRequestHttp().getRequestHttpClient().useProxy(getRequestHttp().getRequestHttpProxy());
173+
}
174+
request.withConnectionProvider(getRequestHttp().getRequestHttpClient());
175+
176+
byte[] bytes = data instanceof ByteArrayInputStream ? ((ByteArrayInputStream) data).readAllBytes() : IOUtils.toByteArray(data);
177+
request.form(getParamName(), data);
178+
179+
HttpResponse response = request.send();
180+
response.charset(StandardCharsets.UTF_8.name());
181+
return response.bodyText();
182+
}
183+
}
184+
}

0 commit comments

Comments
 (0)
Please sign in to comment.