diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaIcpService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaIcpService.java new file mode 100644 index 000000000..ad59b246c --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaIcpService.java @@ -0,0 +1,207 @@ +package me.chanjar.weixin.open.api; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.open.bean.icp.*; +import me.chanjar.weixin.open.bean.result.WxOpenResult; + +import java.io.File; + +/** + * @author xzh + * @Description 小程序备案 + * https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/record/queryIcpVerifyTask.html + * @createTime 2024/08/14 10:52 + */ +public interface WxOpenMaIcpService { + /** + * 查询人脸核身任务状态 + * https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/record/queryIcpVerifyTask.html + */ + String QUERY_ICP_VERIFY_TASK = "https://api.weixin.qq.com/wxa/icp/query_icp_verifytask"; + + /** + * 发起小程序管理员人脸核身 + * https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/record/createIcpVerifyTask.html + */ + String CREATE_ICP_VERIFY_TASK = "https://api.weixin.qq.com/wxa/icp/create_icp_verifytask"; + + /** + * 上传小程序备案媒体材料 + * https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/record/uploadIcpMedia.html + */ + String UPLOAD_ICP_MEDIA = "https://api.weixin.qq.com/wxa/icp/upload_icp_media"; + + /** + * 撤回小程序备案申请 + * https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/record/cancelApplyIcpFiling.html + */ + String CANCEL_APPLY_ICP_FILING = "https://api.weixin.qq.com/wxa/icp/cancel_apply_icp_filing"; + + /** + * 申请小程序备案 + * https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/record/applyIcpFiling.html + */ + String APPLY_ICP_FILING = "https://api.weixin.qq.com/wxa/icp/apply_icp_filing"; + + /** + * 注销小程序备案 + * https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/record/cancelIcpfiling.html + */ + String CANCEL_ICP_FILING = "https://api.weixin.qq.com/wxa/icp/cancel_icp_filing"; + + /** + * 获取小程序备案状态及驳回原因 + * https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/record/getIcpEntranceInfo.html + */ + String GET_ICP_ENTRANCE_INFO = "https://api.weixin.qq.com/wxa/icp/get_icp_entrance_info"; + + /** + * 获取小程序已备案详情 + * https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/record/getOnlineIcpOrder.html + */ + String GET_ONLINE_ICP_ORDER = "https://api.weixin.qq.com/wxa/icp/get_online_icp_order"; + + /** + * 获取小程序服务内容类型 + * https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/record/queryIcpServiceContentTypes.html + */ + String QUERY_ICP_SERVICE_CONTENT_TYPES = "https://api.weixin.qq.com/wxa/icp/query_icp_service_content_types"; + + /** + * 获取证件类型 + * https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/record/queryIcpCertificateTypes.html + */ + String QUERY_ICP_CERTIFICATE_TYPES = "https://api.weixin.qq.com/wxa/icp/query_icp_certificate_types"; + + /** + * 获取区域信息 + * https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/record/queryIcpDistrictCode.html + */ + String QUERY_ICP_DISTRICT_CODE = "https://api.weixin.qq.com/wxa/icp/query_icp_district_code"; + + /** + * 获取前置审批项类型 + * https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/record/queryIcpNrlxTypes.html + */ + String QUERY_ICP_NRLX_TYPES = "https://api.weixin.qq.com/wxa/icp/query_icp_nrlx_types"; + + /** + * 获取单位性质 + * https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/record/queryIcpSubjectTypes.html + */ + String QUERY_ICP_SUBJECT_TYPES = "https://api.weixin.qq.com/wxa/icp/query_icp_subject_types"; + + /** + * 获取小程序备案媒体材料 + * https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/record/getIcpMedia.html + */ + String GET_ICP_MEDIA = "https://api.weixin.qq.com/wxa/icp/get_icp_media"; + + /** + * 查询人脸核身任务状态 + * + * @param taskId 任务id + * @return 人脸核身任务的状态和结果 + * @throws WxErrorException e + */ + WxOpenIcpVerifyTaskResult queryIcpVerifyTask(String taskId) throws WxErrorException; + + /** + * 发起小程序管理员人脸核身 + * + * @return 人脸核验任务结果 + * @throws WxErrorException e + */ + WxOpenIcpCreateIcpVerifyTaskResult createIcpVerifyTask() throws WxErrorException; + + /** + * 上传小程序备案媒体材料 + * + * @param param 备案媒体材料 + * @return 备案媒体材料结果 + * @throws WxErrorException e + */ + WxOpenUploadIcpMediaResult uploadIcpMedia(WxOpenUploadIcpMediaParam param) throws WxErrorException; + + /** + * 撤回小程序备案申请 + * + * @return r + * @throws WxErrorException e + */ + WxOpenResult cancelApplyIcpFiling() throws WxErrorException; + + /** + * 申请小程序备案 + * + * @param param 参数 + * @return r + * @throws WxErrorException e + */ + WxOpenApplyIcpFilingResult applyIcpFiling(WxOpenApplyIcpFilingParam param) throws WxErrorException; + + /** + * 注销小程序备案 + * @param cancelType 注销类型:1 -- 注销主体, 2 -- 注销小程序, 3 -- 注销微信小程序 + * @return r + * @throws WxErrorException e + */ + WxOpenResult cancelIcpFiling(Integer cancelType) throws WxErrorException; + + /** + * 获取小程序备案状态及驳回原因 + * @return r + * @throws WxErrorException e + */ + WxOpenIcpEntranceInfoResult getIcpEntranceInfo() throws WxErrorException; + + /** + * 获取小程序已备案详情 + * @return 已备案详情 + * @throws WxErrorException e + */ + WxOpenOnlineIcpOrderResult getOnlineIcpOrder() throws WxErrorException; + + /** + * 获取小程序服务内容类型 + * @return 小程序服务内容类型定义 + * @throws WxErrorException e + */ + WxOpenQueryIcpServiceContentTypesResult queryIcpServiceContentTypes() throws WxErrorException; + + /** + * 获取证件类型 + * @return 证件类型定义 + * @throws WxErrorException e + */ + WxOpenQueryIcpCertificateTypeResult queryIcpCertificateTypes() throws WxErrorException; + + /** + * 获取区域信息 + * @return 省市区的区域信息 + * @throws WxErrorException e + */ + WxOpenQueryIcpDistrictCodeResult queryIcpDistrictCode() throws WxErrorException; + + /** + * 获取前置审批项类型 + * @return 小程序备案前置审批项类型定义 + * @throws WxErrorException e + */ + WxOpenQueryIcpNrlxTypesResult queryIcpNrlxTypes() throws WxErrorException; + + /** + * 获取单位性质 + * @return 单位性质定义 + * @throws WxErrorException e + */ + WxOpenQueryIcpSubjectTypeResult queryIcpSubjectTypes() throws WxErrorException; + + /** + * 获取小程序备案媒体材料 + * @param mediaId 上传小程序备案媒体材料接口返回的 media_id,示例值:4ahCGpd3CYkE6RpkNkUR5czt3LvG8xDnDdKAz6bBKttSfM8p4k5Rj6823HXugPwQBurgMezyib7 + * @return 所上传的图片或视频媒体材料 + * @throws WxErrorException e + */ + File getIcpMedia(String mediaId) throws WxErrorException; +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java index 2afb5277d..6d540940c 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java @@ -724,6 +724,13 @@ public interface WxOpenMaService extends WxMaService { */ WxOpenMaAuthService getAuthService(); + /** + * 小程序备案服务 + * + * @return 小程序备案服务 + */ + WxOpenMaIcpService getIcpService(); + /** * 小程序用户隐私保护指引服务 * diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaIcpServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaIcpServiceImpl.java new file mode 100644 index 000000000..dc78f22fe --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaIcpServiceImpl.java @@ -0,0 +1,215 @@ +package me.chanjar.weixin.open.api.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +import com.google.gson.JsonObject; +import me.chanjar.weixin.open.bean.CommonUploadMultiParam; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.open.executor.CommonUploadMultiRequestExecutor; +import me.chanjar.weixin.common.util.http.BaseMediaDownloadRequestExecutor; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.open.api.WxOpenMaIcpService; +import me.chanjar.weixin.open.bean.icp.*; +import me.chanjar.weixin.open.bean.result.WxOpenResult; +import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +/** + * @author xzh + * @Description + * @createTime 2024/08/14 14:48 + */ +public class WxOpenMaIcpServiceImpl implements WxOpenMaIcpService { + + private final WxMaService wxMaService; + + public WxOpenMaIcpServiceImpl(WxMaService wxMaService) { + this.wxMaService = wxMaService; + } + + /** + * 查询人脸核身任务状态 + * + * @param taskId 任务id + * @return 人脸核身任务的状态和结果 + * @throws WxErrorException e + */ + @Override + public WxOpenIcpVerifyTaskResult queryIcpVerifyTask(String taskId) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("task_id", taskId); + String response = wxMaService.post(QUERY_ICP_VERIFY_TASK, params); + return WxOpenGsonBuilder.create().fromJson(response, WxOpenIcpVerifyTaskResult.class); + } + + /** + * 发起小程序管理员人脸核身 + * + * @return 人脸核验任务结果 + * @throws WxErrorException e + */ + @Override + public WxOpenIcpCreateIcpVerifyTaskResult createIcpVerifyTask() throws WxErrorException { + String response = wxMaService.post(CREATE_ICP_VERIFY_TASK, ""); + return WxMaGsonBuilder.create().fromJson(response, WxOpenIcpCreateIcpVerifyTaskResult.class); + } + + /** + * 上传小程序备案媒体材料 + * + * @param param 备案媒体材料 + * @return 备案媒体材料结果 + * @throws WxErrorException e + */ + @Override + public WxOpenUploadIcpMediaResult uploadIcpMedia(WxOpenUploadIcpMediaParam param) throws WxErrorException { + RequestExecutor executor = CommonUploadMultiRequestExecutor.create(wxMaService.getRequestHttp()); + String response = wxMaService.execute(executor, UPLOAD_ICP_MEDIA, param.toCommonUploadMultiParam()); + return WxMaGsonBuilder.create().fromJson(response, WxOpenUploadIcpMediaResult.class); + } + + /** + * 撤回小程序备案申请 + * + * @return r + * @throws WxErrorException e + */ + @Override + public WxOpenResult cancelApplyIcpFiling() throws WxErrorException { + String response = wxMaService.post(CANCEL_APPLY_ICP_FILING, ""); + return WxMaGsonBuilder.create().fromJson(response, WxOpenResult.class); + } + + /** + * 申请小程序备案 + * + * @param param 参数 + * @return r + * @throws WxErrorException e + */ + @Override + public WxOpenApplyIcpFilingResult applyIcpFiling(WxOpenApplyIcpFilingParam param) throws WxErrorException { + String response = wxMaService.post(APPLY_ICP_FILING, param); + return WxMaGsonBuilder.create().fromJson(response, WxOpenApplyIcpFilingResult.class); + } + + /** + * 注销小程序备案 + * + * @param cancelType 注销类型:1 -- 注销主体, 2 -- 注销小程序, 3 -- 注销微信小程序 + * @return r + * @throws WxErrorException e + */ + @Override + public WxOpenResult cancelIcpFiling(Integer cancelType) throws WxErrorException { + JsonObject params = new JsonObject(); + params.addProperty("cancel_type", cancelType); + String response = wxMaService.post(CANCEL_ICP_FILING, params); + return WxOpenGsonBuilder.create().fromJson(response, WxOpenResult.class); + } + + /** + * 获取小程序备案状态及驳回原因 + * + * @return r + * @throws WxErrorException e + */ + @Override + public WxOpenIcpEntranceInfoResult getIcpEntranceInfo() throws WxErrorException { + String response = wxMaService.get(GET_ICP_ENTRANCE_INFO, null); + return WxMaGsonBuilder.create().fromJson(response, WxOpenIcpEntranceInfoResult.class); + } + + /** + * 获取小程序已备案详情 + * + * @return 已备案详情 + * @throws WxErrorException e + */ + @Override + public WxOpenOnlineIcpOrderResult getOnlineIcpOrder() throws WxErrorException { + String response = wxMaService.get(GET_ONLINE_ICP_ORDER, null); + return WxMaGsonBuilder.create().fromJson(response, WxOpenOnlineIcpOrderResult.class); + } + + /** + * 获取小程序服务内容类型 + * + * @return 小程序服务内容类型定义 + * @throws WxErrorException e + */ + @Override + public WxOpenQueryIcpServiceContentTypesResult queryIcpServiceContentTypes() throws WxErrorException { + String response = wxMaService.get(QUERY_ICP_SERVICE_CONTENT_TYPES, null); + return WxMaGsonBuilder.create().fromJson(response, WxOpenQueryIcpServiceContentTypesResult.class); + } + + /** + * 获取证件类型 + * + * @return 证件类型定义 + * @throws WxErrorException e + */ + @Override + public WxOpenQueryIcpCertificateTypeResult queryIcpCertificateTypes() throws WxErrorException { + String response = wxMaService.get(QUERY_ICP_CERTIFICATE_TYPES, null); + return WxMaGsonBuilder.create().fromJson(response, WxOpenQueryIcpCertificateTypeResult.class); + } + + /** + * 获取区域信息 + * + * @return 省市区的区域信息 + * @throws WxErrorException e + */ + @Override + public WxOpenQueryIcpDistrictCodeResult queryIcpDistrictCode() throws WxErrorException { + String response = wxMaService.get(QUERY_ICP_DISTRICT_CODE, null); + return WxMaGsonBuilder.create().fromJson(response, WxOpenQueryIcpDistrictCodeResult.class); + } + + /** + * 获取前置审批项类型 + * + * @return 小程序备案前置审批项类型定义 + * @throws WxErrorException e + */ + @Override + public WxOpenQueryIcpNrlxTypesResult queryIcpNrlxTypes() throws WxErrorException { + String response = wxMaService.get(QUERY_ICP_NRLX_TYPES, null); + return WxMaGsonBuilder.create().fromJson(response, WxOpenQueryIcpNrlxTypesResult.class); + } + + /** + * 获取单位性质 + * + * @return 单位性质定义 + * @throws WxErrorException e + */ + @Override + public WxOpenQueryIcpSubjectTypeResult queryIcpSubjectTypes() throws WxErrorException { + String response = wxMaService.get(QUERY_ICP_SUBJECT_TYPES, null); + return WxMaGsonBuilder.create().fromJson(response, WxOpenQueryIcpSubjectTypeResult.class); + } + + /** + * 获取小程序备案媒体材料 + * @param mediaId 上传小程序备案媒体材料接口返回的 media_id,示例值:4ahCGpd3CYkE6RpkNkUR5czt3LvG8xDnDdKAz6bBKttSfM8p4k5Rj6823HXugPwQBurgMezyib7 + * @return 所上传的图片或视频媒体材料 + * @throws WxErrorException e + */ + @Override + public File getIcpMedia(String mediaId) throws WxErrorException { + try { + RequestExecutor executor = BaseMediaDownloadRequestExecutor + .create(this.wxMaService.getRequestHttp(), Files.createTempDirectory("wxma").toFile()); + return this.wxMaService.execute(executor, GET_ICP_MEDIA, "media_id=" + mediaId); + } catch (IOException e) { + throw new WxErrorException(WxError.builder().errorMsg(e.getMessage()).build(), e); + } + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java index fd6560192..75be6bd4e 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java @@ -49,6 +49,8 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ @Getter private final WxOpenMaAuthService authService; @Getter + private final WxOpenMaIcpService icpService; + @Getter private final WxOpenMaPrivacyService privacyService; @Getter private final WxOpenMaShoppingOrdersService shoppingOrdersService; @@ -59,6 +61,7 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ this.wxMaConfig = wxMaConfig; this.basicService = new WxOpenMaBasicServiceImpl(this); this.authService = new WxOpenMaAuthServiceImpl(this); + this.icpService = new WxOpenMaIcpServiceImpl(this); this.privacyService = new WxOpenMaPrivacyServiceImpl(this); this.shoppingOrdersService = new WxOpenMaShoppingOrdersServiceImpl(this); initHttp(); diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/CommonUploadMultiParam.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/CommonUploadMultiParam.java new file mode 100644 index 000000000..b3bcd1b1b --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/CommonUploadMultiParam.java @@ -0,0 +1,39 @@ +package me.chanjar.weixin.open.bean; + +import lombok.Builder; +import lombok.Data; +import me.chanjar.weixin.common.bean.CommonUploadParam; + +import java.io.Serializable; +import java.util.List; + +/** + * @author xzh + * @Description + * @createTime 2024/08/14 16:20 + */ +@Data +@Builder +public class CommonUploadMultiParam implements Serializable { + private static final long serialVersionUID = -7935687108401829869L; + + private List normalParams; + + private CommonUploadParam uploadParam; + + @Data + @Builder + public static class NormalParam implements Serializable { + private static final long serialVersionUID = 4345164516827726194L; + + /** + * 参数名称(非文件名),如:type + */ + private String name; + + /** + * 参数名称对应值,如:image + */ + private String value; + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenApplyIcpFilingParam.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenApplyIcpFilingParam.java new file mode 100644 index 000000000..37f84cf3d --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenApplyIcpFilingParam.java @@ -0,0 +1,557 @@ +package me.chanjar.weixin.open.bean.icp; + +import com.google.gson.annotations.SerializedName; +import lombok.*; + +import java.io.Serializable; +import java.util.List; + +/** + * @author xzh + * @Description + * @createTime 2024/08/14 15:09 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WxOpenApplyIcpFilingParam implements Serializable { + + private static final long serialVersionUID = -1175687030580685304L; + + /** + * 备案主体信息 + */ + @SerializedName("icp_subject") + private Subject icpSubject; + + /** + * 微信小程序信息 + */ + @SerializedName("icp_applets") + private Applets icpApplets; + + /** + * 其他备案媒体材料 + */ + @SerializedName("icp_materials") + private Materials icpMaterials; + + //region Subject define + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Subject implements Serializable { + + private static final long serialVersionUID = -3760060095514905158L; + + /** + * 主体基本信息 + */ + @SerializedName("base_info") + private SubjectBaseInfo baseInfo; + + /** + * 个人主体额外信息 + */ + @SerializedName("personal_info") + private SubjectPersonalInfo personalInfo; + + /** + * 主体额外信息(个人备案时,如果存在与主体负责人信息相同的字段,则填入相同的值) + */ + @SerializedName("organize_info") + private SubjectOrganizeInfo organizeInfo; + + /** + * 主体负责人信息 + */ + @SerializedName("principal_info") + private SubjectPrincipalInfo principalInfo; + + /** + * 法人信息(非个人备案,且主体负责人不是法人时,必填) + */ + @SerializedName("legal_person_info") + private SubjectLegaPersonInfo legalPersonInfo; + + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class SubjectBaseInfo implements Serializable { + private static final long serialVersionUID = 6040247507213564709L; + + /** + * 主体性质,示例值:5 + */ + @SerializedName("type") + private Integer type; + + /** + * 主办单位名称 + */ + @SerializedName("name") + private String name; + + /** + * 备案省份 + * 使用省份代码,示例值:"110000"(参考:获取区域信息接口) + */ + @SerializedName("province") + private String province; + + /** + * 备案城市 + * 使用城市代码,示例值:"110100"(参考:获取区域信息接口) + */ + @SerializedName("city") + private String city; + + /** + * 备案县区 + * 使用县区代码,示例值:"110105"(参考:获取区域信息接口) + */ + @SerializedName("district") + private String district; + + /** + * 通讯地址,必须属于备案省市区,地址开头的省市区不用填入, + * 例如:通信地址为“北京市朝阳区高碑店路181号1栋12345室”时, + * 只需要填写 "高碑店路181号1栋12345室" 即可 + */ + @SerializedName("address") + private String address; + + /** + * 主体信息备注,根据需要,如实填写 + */ + @SerializedName("comment") + private String comment; + + /** + * 主体备案号,示例值:粤B2-20090059(申请小程序备案时不用填写,查询已备案详情时会返回) + */ + @SerializedName("record_number") + private String recordNumber; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class SubjectPersonalInfo implements Serializable { + private static final long serialVersionUID = 2453569107311102079L; + + /** + * 临时居住证明照片 media_id,个人备案且非本省人员,需要提供居住证、暂住证、社保证明、房产证等临时居住证明, + */ + @SerializedName("residence_permit") + private String residencePermit; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class SubjectOrganizeInfo implements Serializable { + private static final long serialVersionUID = 562578565445293345L; + + /** + * 主体证件类型, + * 示例值:2(参考:获取证件类型接口) + */ + @SerializedName("certificate_type") + private Integer certificateType; + + /** + * 主体证件号码, + * 示例值:"110105199001011234" + */ + @SerializedName("certificate_number") + private String certificateNumber; + + /** + * 主体证件住所, + * 示例值:"北京市朝阳区高碑店路181号1栋12345室" + */ + @SerializedName("certificate_address") + private String certificateAddress; + + /** + * 主体证件照片 media_id, + * 如果小程序主体为非个人类型,则必填 + */ + @SerializedName("certificate_photo") + private String certificatePhoto; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class SubjectPrincipalInfo implements Serializable { + + private static final long serialVersionUID = -6840245946309353916L; + + /** + * 负责人姓名 + */ + @SerializedName("name") + private String name; + + /** + * 负责人联系方式 + */ + @SerializedName("mobile") + private String mobile; + + /** + * 负责人电子邮件 + */ + @SerializedName("email") + private String email; + + /** + * 负责人应急联系方式 + */ + @SerializedName("emergency_contact") + private String emergencyContact; + + /** + * 负责人证件类型 + */ + @SerializedName("certificate_type") + private Integer certificateType; + + /** + * 负责人证件号码 + */ + @SerializedName("certificate_number") + private String certificateNumber; + + /** + * 负责人证件有效期起始日期 + * 格式为 YYYYmmdd,示例值:"20230815" + */ + @SerializedName("certificate_validity_date_start") + private String certificateValidityDateStart; + + /** + * 负责人证件有效期终止日期 + * 格式为 YYYYmmdd,如证件长期有效,请填写 "长期",示例值:"20330815" + */ + @SerializedName("certificate_validity_date_end") + private String certificateValidityDateEnd; + + /** + * 负责人证件正面照片 media_id(身份证为人像面) + */ + @SerializedName("certificate_photo_front") + private String certificatePhotoFront; + + /** + * 负责人证件背面照片 media_id + */ + @SerializedName("certificate_photo_back") + private String certificatePhotoBack; + + /** + * 授权书 media_id,当主体负责人不是法人时需要主体负责人授权书, + * 当小程序负责人不是法人时需要小程序负责人授权书 + */ + @SerializedName("authorization_letter") + private String authorizationLetter; + + /** + * 扫脸认证任务id(扫脸认证接口返回的task_id), + * 仅小程序负责人需要扫脸,主体负责人无需扫脸, + */ + @SerializedName("verify_task_id") + private String verifyTaskId; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class SubjectLegaPersonInfo implements Serializable { + + private static final long serialVersionUID = -7386716346559073571L; + + /** + * 法人代表姓名 + */ + @SerializedName("name") + private String name; + + /** + * 法人证件号码 + */ + @SerializedName("certificate_number") + private String certificateNumber; + } + + //endregion Subject define + + //region Applets define + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Applets implements Serializable { + + private static final long serialVersionUID = -2938469180388648595L; + + /** + * 微信小程序基本信息 + */ + @SerializedName("base_info") + private AppletsBaseInfo basInfo; + + /** + * 小程序负责人信息 + */ + @SerializedName("principal_info") + private AppletsPrincipalInfo principalInfo; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class AppletsBaseInfo implements Serializable { + + private static final long serialVersionUID = 8404017028547715919L; + + /** + * 小程序ID,不用填写,后台自动拉取 + */ + @SerializedName("appid") + private String appId; + + /** + * 小程序名称,不用填写,后台自动拉取 + */ + @SerializedName("name") + private String name; + + /** + * 小程序服务内容类型,只能填写二级服务内容类型,最多5个 + */ + @SerializedName("service_content_types") + private List serviceContentTypes; + + /** + * 前置审批项,列表中不能存在重复的前置审批类型id,如不涉及前置审批项,也需要填“以上都不涉及” + */ + @SerializedName("nrlx_details") + private List nrlxDetails; + + /** + * 请具体描述小程序实际经营内容、主要服务内容,该信息为主管部门审核重要依据,备注内容字数限制20-200字,请认真填写。 + */ + @SerializedName("comment") + private String comment; + + /** + * 小程序备案号,示例值:粤B2-20090059-1626X + * (申请小程序备案时不用填写,查询已备案详情时会返回) + */ + @SerializedName("record_number") + private String recordNumber; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class AppletsNrlxDetailItem implements Serializable { + + private static final long serialVersionUID = -9144721738792167000L; + + /** + * 前置审批类型,示例值:2 + * (参考:获取前置审批项接口) + */ + @SerializedName("type") + private Integer type; + + /** + * 前置审批号,如果前置审批类型不是“以上都不涉及”, + * 则必填,示例值:"粤-12345号 + */ + @SerializedName("code") + private String code; + + /** + * 前置审批媒体材料 media_id + */ + @SerializedName("media") + private String media; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class AppletsPrincipalInfo implements Serializable { + + private static final long serialVersionUID = 5088256283066784463L; + + /** + * 负责人姓名 + */ + @SerializedName("name") + private String name; + + /** + * 负责人联系方式 + */ + @SerializedName("mobile") + private String mobile; + + /** + * 负责人电子邮件 + */ + @SerializedName("email") + private String email; + + /** + * 负责人应急联系方式 + */ + @SerializedName("emergency_contact") + private String emergencyContact; + + /** + * 负责人证件类型,示例值:2(参考:获取证件类型接口,此处只能填入单位性质属于个人的证件类型) + */ + @SerializedName("certificate_type") + private Integer certificateType; + + /** + * 负责人证件号码 + */ + @SerializedName("certificate_number") + private String certificateNumber; + + /** + * 负责人证件有效期起始日期, + * 格式为 YYYYmmdd,示例值:"20230815" + */ + @SerializedName("certificate_validity_date_start") + private String certificateValidityDateStart; + + /** + * 负责人证件有效期终止日期, + * 格式为 YYYYmmdd, + * 如证件长期有效,请填写 "长期",示例值:"20330815" + */ + @SerializedName("certificate_validity_date_end") + private String certificateValidityDateEnd; + + /** + * 负责人证件正面照片 media_id + * (身份证为人像面) + */ + @SerializedName("certificate_photo_front") + private String certificatePhotoFront; + + /** + * 负责人证件背面照片 media_id + * (身份证为国徽面) + */ + @SerializedName("certificate_photo_back") + private String certificatePhotoBack; + + /** + * 授权书 media_id, + * 当主体负责人不是法人时需要主体负责人授权书, + * 当小程序负责人不是法人时需要小程序负责人授权书 + */ + @SerializedName("authorization_letter") + private String authorizationLetter; + + /** + * 扫脸认证任务id(扫脸认证接口返回的task_id), + * 仅小程序负责人需要扫脸,主体负责人无需扫脸 + */ + @SerializedName("verify_task_id") + private String verifyTaskId; + } + //endregion Applets define + + //region Materials define + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Materials { + + /** + * 互联网信息服务承诺书 media_id,最多上传1个 + */ + @SerializedName("commitment_letter") + private List commitmentLetter; + + /** + * 主体更名函 media_id(非个人类型,且发生过更名时需要上传),最多上传1个 + */ + @SerializedName("business_name_change_letter") + private List businessNameChangeLetter; + + /** + * 党建确认函 media_id,最多上传1个 + */ + @SerializedName("party_building_confirmation_letter") + private List partyBuildingConfirmationLetter; + + /** + * 承诺视频 media_id,最多上传1个 + */ + @SerializedName("promise_video") + private List promiseVideo; + + /** + * 网站备案信息真实性责任告知书 media_id,最多上传1个 + */ + @SerializedName("authenticity_responsibility_letter") + private List authenticityResponsibilityLetter; + + /** + * 小程序备案信息真实性承诺书 media_id,最多上传1个 + */ + @SerializedName("authenticity_commitment_letter") + private List authenticityCommitmentLetter; + + /** + * 小程序建设方案书 media_id,最多上传1个 + */ + @SerializedName("website_construction_proposal") + private List websiteConstructionProposal; + + /** + * 主体其它附件 media_id,最多上传10个 + */ + @SerializedName("subject_other_materials") + private List subjectOtherMaterials; + + /** + * 小程序其它附件 media_id,最多上传10个 + */ + @SerializedName("applets_other_materials") + private List appletsOtherMaterials; + + /** + * 手持证件照 media_id,最多上传1个 + */ + @SerializedName("holding_certificate_photo") + private List holdingCertificatePhoto; + } + //endregion Materials define +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenApplyIcpFilingResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenApplyIcpFilingResult.java new file mode 100644 index 000000000..223e5944f --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenApplyIcpFilingResult.java @@ -0,0 +1,40 @@ +package me.chanjar.weixin.open.bean.icp; + +import java.util.List; + +import com.google.gson.annotations.SerializedName; + +import lombok.*; +import me.chanjar.weixin.open.bean.result.WxOpenResult; + + +/** + * @author xzh + * @Description 申请小程序备案 + * @createTime 2024/08/14 10:52 + */ +@Getter +@Setter +@NoArgsConstructor +public class WxOpenApplyIcpFilingResult extends WxOpenResult { + private static final long serialVersionUID = 9215343492997218227L; + + /** + * 错误提示 + */ + @SerializedName("hints") + private List hints; + + @Data + @EqualsAndHashCode(callSuper = true) + public static class Hint extends WxOpenResult { + + private static final long serialVersionUID = 6585787444231217123L; + + /** + * 校验失败的字段 + */ + @SerializedName("err_field") + private String errField; + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenIcpCreateIcpVerifyTaskResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenIcpCreateIcpVerifyTaskResult.java new file mode 100644 index 000000000..782db16e9 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenIcpCreateIcpVerifyTaskResult.java @@ -0,0 +1,28 @@ +package me.chanjar.weixin.open.bean.icp; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import me.chanjar.weixin.open.bean.result.WxOpenResult; + +/** + * @author xzh + * @Description 人脸核验任务结果 + * @createTime 2024/08/14 10:52 + */ +@Getter +@Setter +@NoArgsConstructor +public class WxOpenIcpCreateIcpVerifyTaskResult extends WxOpenResult { + + private static final long serialVersionUID = -8960874090439615220L; + + /** + * 人脸核验任务id + */ + @JsonProperty("task_id") + private String taskId; + +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenIcpEntranceInfoResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenIcpEntranceInfoResult.java new file mode 100644 index 000000000..9538a64b0 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenIcpEntranceInfoResult.java @@ -0,0 +1,92 @@ +package me.chanjar.weixin.open.bean.icp; + +import com.google.gson.annotations.SerializedName; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import me.chanjar.weixin.open.bean.result.WxOpenResult; + +import java.io.Serializable; + + +/** + * @author xzh + * @Description 获取小程序备案状态及驳回原因 + * @createTime 2024/08/14 10:52 + */ +@Getter +@Setter +@NoArgsConstructor +public class WxOpenIcpEntranceInfoResult extends WxOpenResult { + + private static final long serialVersionUID = 4661275080517814216L; + + /** + * 备案状态信息 + */ + private Info info; + + @Getter + @Setter + @NoArgsConstructor + public static class Info implements Serializable { + + private static final long serialVersionUID = 879913578935521216L; + + /** + * 备案状态,取值参考备案状态枚举,示例值:1024 + */ + @SerializedName("status") + private Integer status; + + /** + * 是否正在注销备案 + */ + @SerializedName("is_canceling") + private Boolean canceling; + + /** + * 驳回原因,备案不通过时返回 + */ + @SerializedName("audit_data") + private AuditData auditData; + + /** + * 备案入口是否对该小程序开放,0:不开放,1:开放。特定情况下入口不会开放,如小程序昵称包含某些关键词时、管局系统不可用时,当备案入口开放时才能提交备案申请 + */ + @SerializedName("available") + private Integer available; + + /** + * 管局短信核验状态,仅当备案状态为 4(管局审核中)的时候才有效。1:等待核验中,2:核验完成,3:核验超时。 + */ + @SerializedName("sms_verify_status") + private Integer smsVerifyStatus; + } + + @Getter + @Setter + @NoArgsConstructor + public static class AuditData implements Serializable { + + private static final long serialVersionUID = 2217833539540191890L; + + /** + * 审核不通过的字段中文名 + */ + @SerializedName("key_name") + private String keyName; + + /** + * 字段不通过的原因 + */ + @SerializedName("error") + private String error; + + /** + * 修改建议 + */ + @SerializedName("suggest") + private String suggest; + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenIcpVerifyTaskResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenIcpVerifyTaskResult.java new file mode 100644 index 000000000..cb59fac1c --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenIcpVerifyTaskResult.java @@ -0,0 +1,33 @@ +package me.chanjar.weixin.open.bean.icp; + +import com.google.gson.annotations.SerializedName; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import me.chanjar.weixin.open.bean.result.WxOpenResult; + +/** + * @author xzh + * @Description 人脸核身任务的状态和结果 + * @createTime 2024/08/14 10:52 + */ +@Getter +@Setter +@NoArgsConstructor +public class WxOpenIcpVerifyTaskResult extends WxOpenResult { + + private static final long serialVersionUID = 3134332406149779364L; + + /** + * 人脸核身任务是否已完成 + */ + @SerializedName("is_finish") + private Boolean finish; + + /** + * 任务状态枚举:0. 未开始;1. 等待中;2. 失败;3. 成功。返回的 is_finish 字段为 true 时,face_status 才是最终状态。 + */ + @SerializedName("face_status") + private Integer faceStatus; +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenOnlineIcpOrderResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenOnlineIcpOrderResult.java new file mode 100644 index 000000000..89f8e8c39 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenOnlineIcpOrderResult.java @@ -0,0 +1,36 @@ +package me.chanjar.weixin.open.bean.icp; + +import java.io.Serializable; +import java.util.List; + +import com.google.gson.annotations.SerializedName; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + + +/** + * @author xzh + * @Description 已备案详情 + * @createTime 2024/08/14 10:52 + */ +@Getter +@Setter +@NoArgsConstructor +public class WxOpenOnlineIcpOrderResult implements Serializable { + + private static final long serialVersionUID = -8670174116784375577L; + + /** + * 备案主体信息 + */ + @SerializedName("icp_subject") + private WxOpenApplyIcpFilingParam.Subject icpSubject; + + /** + * 微信小程序信息 + */ + @SerializedName("icp_applets") + private WxOpenApplyIcpFilingParam.Applets icpApplets; +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenQueryIcpCertificateTypeResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenQueryIcpCertificateTypeResult.java new file mode 100644 index 000000000..5e042b4cb --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenQueryIcpCertificateTypeResult.java @@ -0,0 +1,50 @@ +package me.chanjar.weixin.open.bean.icp; + +import java.io.Serializable; +import java.util.List; + +import com.google.gson.annotations.SerializedName; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import me.chanjar.weixin.open.bean.result.WxOpenResult; + +/** + * @author xzh + * @Description 证件类型定义 + * @createTime 2024/08/14 10:52 + */ +@Getter +@Setter +@NoArgsConstructor +public class WxOpenQueryIcpCertificateTypeResult extends WxOpenResult { + + private static final long serialVersionUID = -6492653564753189104L; + + /** + * 证件类型列表 + */ + @SerializedName("items") + private List items; + + @Getter + @Setter + @NoArgsConstructor + public static class Item implements Serializable { + + private static final long serialVersionUID = -5353506906838811002L; + + @SerializedName("type") + private Integer type; + + @SerializedName("subject_type") + private Integer subjectType; + + @SerializedName("name") + private String name; + + @SerializedName("remark") + private String remark; + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenQueryIcpDistrictCodeResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenQueryIcpDistrictCodeResult.java new file mode 100644 index 000000000..28ca0ef5c --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenQueryIcpDistrictCodeResult.java @@ -0,0 +1,58 @@ +package me.chanjar.weixin.open.bean.icp; + +import java.io.Serializable; +import java.util.List; + +import com.google.gson.annotations.SerializedName; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import me.chanjar.weixin.open.bean.result.WxOpenResult; + +/** + * @author xzh + * @Description 省市区的区域信息 + * @createTime 2024/08/14 10:52 + */ +@Getter +@Setter +@NoArgsConstructor +public class WxOpenQueryIcpDistrictCodeResult extends WxOpenResult { + private static final long serialVersionUID = -5087976503275542589L; + + @SerializedName("items") + private List items; + + @Getter + @Setter + @NoArgsConstructor + public static class Item implements Serializable { + + private static final long serialVersionUID = -8598323103982035055L; + + /** + * 区域类型: 1 -- 省份,2 -- 市,3 -- 区 + */ + @SerializedName("type") + private Integer type; + + /** + * 区域代码 + */ + @SerializedName("code") + private Integer code; + + /** + * 下级区域信息列表 + */ + @SerializedName("name") + private String name; + + /** + * 下级区域信息列表 + */ + @SerializedName("sub_list") + private List subList; + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenQueryIcpNrlxTypesResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenQueryIcpNrlxTypesResult.java new file mode 100644 index 000000000..e87702989 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenQueryIcpNrlxTypesResult.java @@ -0,0 +1,50 @@ +package me.chanjar.weixin.open.bean.icp; + +import java.io.Serializable; +import java.util.List; + +import com.google.gson.annotations.SerializedName; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import me.chanjar.weixin.open.bean.result.WxOpenResult; + + +/** + * @author xzh + * @Description 小程序备案前置审批项类型定义 + * @createTime 2024/08/14 10:52 + */ +@Getter +@Setter +@NoArgsConstructor +public class WxOpenQueryIcpNrlxTypesResult extends WxOpenResult { + private static final long serialVersionUID = 4986067025882451072L; + + /** + * 前置审批项类型列表 + */ + @SerializedName("items") + private List items; + + @Getter + @Setter + @NoArgsConstructor + public static class Item implements Serializable { + + private static final long serialVersionUID = 9069126796573950000L; + + /** + * 前置审批项类型id + */ + @SerializedName("type") + private Integer type; + + /** + * 名称 + */ + @SerializedName("name") + private String name; + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenQueryIcpServiceContentTypesResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenQueryIcpServiceContentTypesResult.java new file mode 100644 index 000000000..1d800fbab --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenQueryIcpServiceContentTypesResult.java @@ -0,0 +1,60 @@ +package me.chanjar.weixin.open.bean.icp; + +import java.io.Serializable; +import java.util.List; + +import com.google.gson.annotations.SerializedName; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import me.chanjar.weixin.open.bean.result.WxOpenResult; + + +/** + * @author xzh + * @Description 小程序服务内容类型 + * @createTime 2024/08/14 10:52 + */ +@Getter +@Setter +@NoArgsConstructor +public class WxOpenQueryIcpServiceContentTypesResult extends WxOpenResult { + private static final long serialVersionUID = 2982244171428787389L; + + /** + * 服务内容类型列表 + */ + private List items; + + @Getter + @Setter + @NoArgsConstructor + public static class Item implements Serializable { + + private static final long serialVersionUID = 1432103347845426732L; + + /** + * 服务内容类型id + */ + @SerializedName("type") + private Integer type; + + /** + * 该服务内容类型的父类型id + */ + @SerializedName("parent_type") + private Integer parentType; + + /** + * 名称 + */ + @SerializedName("name") + private String name; + + /** + * 备注 + */ + @SerializedName("remark") + private String remark; + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenQueryIcpSubjectTypeResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenQueryIcpSubjectTypeResult.java new file mode 100644 index 000000000..a03e056db --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenQueryIcpSubjectTypeResult.java @@ -0,0 +1,53 @@ +package me.chanjar.weixin.open.bean.icp; + +import java.io.Serializable; +import java.util.List; + +import com.google.gson.annotations.SerializedName; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * @author xzh + * @Description 单位性质定义 + * @createTime 2024/08/14 10:52 + */ +@Getter +@Setter +@NoArgsConstructor +public class WxOpenQueryIcpSubjectTypeResult implements Serializable { + + private static final long serialVersionUID = -2090825609788654435L; + + /** + * 单位性质列表 + */ + private List items; + + @Getter + @Setter + @NoArgsConstructor + public static class Item implements Serializable { + + private static final long serialVersionUID = -1284830856404207970L; + + /** + * 单位性质类型id + */ + @SerializedName("type") + private Integer type; + + /** + * 名称 + */ + @SerializedName("name") + private String name; + + /** + * 备注 + */ + @SerializedName("remark") + private String remark; + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenUploadIcpMediaParam.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenUploadIcpMediaParam.java new file mode 100644 index 000000000..a5eda8ab4 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenUploadIcpMediaParam.java @@ -0,0 +1,64 @@ +package me.chanjar.weixin.open.bean.icp; + +import java.io.Serializable; +import java.util.*; + +import com.google.gson.annotations.SerializedName; + +import lombok.*; +import me.chanjar.weixin.common.bean.CommonUploadData; +import me.chanjar.weixin.open.bean.CommonUploadMultiParam; +import me.chanjar.weixin.common.bean.CommonUploadParam; + + +/** + * @author xzh + * @Description 文件上传 + * @createTime 2024/08/14 10:52 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WxOpenUploadIcpMediaParam implements Serializable { + + private static final long serialVersionUID = -9082174509776922969L; + + /** + * 媒体材料类型。目前支持两种:图片("image")和视频("video"),示例值:"image" + */ + @SerializedName("type") + private String type; + + /** + * 证件类型(参考:获取证件类型),如果上传的是证件媒体材料,则必填,示例值:2 + */ + @SerializedName("certificate_type") + private String certificateType; + + /** + * 媒体材料所属的备案字段名(参考:申请小程序备案接口),如要用于多个备案字段,则填写其中一个字段名即可。 + * 例如:要上传身份证头像面照片作为备案主体负责人和小程序负责人的证件照正面, 就填写 + * "icp_subject.principal_info.certificate_photo_front" + */ + @SerializedName("icp_order_field") + private String icpOrderField; + + /** + * 待上传的图片或视频 + */ + private CommonUploadData media; + + + public CommonUploadMultiParam toCommonUploadMultiParam() { + return CommonUploadMultiParam.builder() + .normalParams(Arrays.asList( + CommonUploadMultiParam.NormalParam.builder().name("type").value(type).build(), + CommonUploadMultiParam.NormalParam.builder().name("certificate_type").value(certificateType).build(), + CommonUploadMultiParam.NormalParam.builder().name("icp_order_field").value(icpOrderField).build() + )) + .uploadParam(new CommonUploadParam("media", media)) + .build(); + } + +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenUploadIcpMediaResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenUploadIcpMediaResult.java new file mode 100644 index 000000000..04977113e --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenUploadIcpMediaResult.java @@ -0,0 +1,40 @@ +package me.chanjar.weixin.open.bean.icp; + +import com.google.gson.annotations.SerializedName; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +import me.chanjar.weixin.open.bean.result.WxOpenResult; + +/** + * @author xzh + * @Description 上传小程序备案媒体材料结果 + * @createTime 2024/08/14 10:52 + */ +@Getter +@Setter +@NoArgsConstructor +public class WxOpenUploadIcpMediaResult extends WxOpenResult { + + private static final long serialVersionUID = 6929154695595201734L; + + /** + * 媒体材料类型。目前支持两种:图片("image")和视频("video"),示例值:"image" + */ + @SerializedName("type") + private String type; + + /** + * 媒体id,示例值:"4ahCGpd3CYkE6RpkNkUR5czt3LvG8xDnDdKAz6bBKttSfM8p4k5Rj6823HXugPwQBurgMezyib7" + */ + @SerializedName("media_id") + private String mediaId; + + /** + * 创建时间,UNIX时间戳,示例值:1692883651 + */ + @SerializedName("created_at") + private String createdAt; +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessage.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessage.java index f8bde1582..e676f0ab6 100644 --- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessage.java +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessage.java @@ -123,6 +123,37 @@ public class WxOpenXmlMessage implements Serializable { @XStreamAlias("expired") private Long expired; + //region 以下为小程序管理员人脸核身完成事件 推送的消息 infoType=notify_icpfiling_verify_result + + /** + * 人脸核验任务id + */ + @XStreamAlias("task_id") + private String IcpVerifyTaskId; + /** + * 小程序唯一id + */ + @XStreamAlias("verify_appid") + private String verifyAppId; + /** + * 人脸核验结果: 2-核验失败;3-核验成功 + */ + @XStreamAlias("result") + private Integer result; + //endregion + + //region 当备案审核被驳回或通过时会推送该事件 推送的消息 infoType=notify_apply_icpfiling_result + /** + * 小程序唯一id + */ + @XStreamAlias("authorizer_appid") + private String authorizerAppId; + /** + * 备案状态,参考“获取小程序备案状态及驳回原因”接口的备案状态枚举¬ + */ + @XStreamAlias("beian_status") + private Integer beianStatus; + //endregion /** * 快速创建的小程序appId,已弃用,未来将删除 diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutor.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutor.java new file mode 100644 index 000000000..4812dd325 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutor.java @@ -0,0 +1,49 @@ +package me.chanjar.weixin.open.executor; + +import me.chanjar.weixin.open.bean.CommonUploadMultiParam; +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 xzh + * @Description + * @createTime 2024/08/14 16:28 + */ +public abstract class CommonUploadMultiRequestExecutor implements RequestExecutor { + + protected RequestHttp requestHttp; + + public CommonUploadMultiRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; + } + + @Override + public void execute(String uri, CommonUploadMultiParam data, ResponseHandler handler, WxType wxType) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data, wxType)); + } + + /** + * 构造通用文件上传执行器 + * + * @param requestHttp 请求信息 + * @return 执行器 + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static RequestExecutor create(RequestHttp requestHttp) { + switch (requestHttp.getRequestType()) { + case APACHE_HTTP: + return new CommonUploadMultiRequestExecutorApacheImpl(requestHttp); + case JODD_HTTP: + return new CommonUploadMultiRequestExecutorJoddHttpImpl(requestHttp); + case OK_HTTP: + return new CommonUploadMultiRequestExecutorOkHttpImpl(requestHttp); + default: + throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType()); + } + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorApacheImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorApacheImpl.java new file mode 100644 index 000000000..2d386ea5d --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorApacheImpl.java @@ -0,0 +1,95 @@ +package me.chanjar.weixin.open.executor; + +import lombok.Getter; +import me.chanjar.weixin.common.bean.CommonUploadData; +import me.chanjar.weixin.open.bean.CommonUploadMultiParam; +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.Consts; +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.entity.mime.content.StringBody; +import org.apache.http.impl.client.CloseableHttpClient; +import org.springframework.util.CollectionUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +/** + * @author xzh + * @Description + * @createTime 2024/08/14 16:28 + */ +public class CommonUploadMultiRequestExecutorApacheImpl extends CommonUploadMultiRequestExecutor { + + public CommonUploadMultiRequestExecutorApacheImpl(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public String execute(String uri, CommonUploadMultiParam 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) { + MultipartEntityBuilder entity = MultipartEntityBuilder.create(); + + List normalParams = param.getNormalParams(); + if (!CollectionUtils.isEmpty(normalParams)) { + for (CommonUploadMultiParam.NormalParam normalParam : normalParams) { + entity.addPart(normalParam.getName(), new StringBody(normalParam.getValue(), ContentType.create("multipart/form-data", Consts.UTF_8))); + } + } + + CommonUploadParam uploadParam = param.getUploadParam(); + if (uploadParam != null) { + CommonUploadData data = uploadParam.getData(); + InnerStreamBody part = new InnerStreamBody(data.getInputStream(), ContentType.DEFAULT_BINARY, data.getFileName(), data.getLength()); + entity.addPart(uploadParam.getName(), part) + .setMode(HttpMultipartMode.RFC6532); + } + + httpPost.setEntity(entity.build()); + } + 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; + } + } +} diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorJoddHttpImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorJoddHttpImpl.java new file mode 100644 index 000000000..1650c1674 --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorJoddHttpImpl.java @@ -0,0 +1,109 @@ +package me.chanjar.weixin.open.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.open.bean.CommonUploadMultiParam; +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 org.apache.http.Consts; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.content.StringBody; +import org.springframework.util.CollectionUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +/** + * @author xzh + * @Description + * @createTime 2024/08/14 16:43 + */ +public class CommonUploadMultiRequestExecutorJoddHttpImpl extends CommonUploadMultiRequestExecutor { + + public CommonUploadMultiRequestExecutorJoddHttpImpl(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public String execute(String uri, CommonUploadMultiParam param, WxType wxType) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (requestHttp.getRequestHttpProxy() != null) { + requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy()); + } + request.withConnectionProvider(requestHttp.getRequestHttpClient()); + + List normalParams = param.getNormalParams(); + if (!CollectionUtils.isEmpty(normalParams)) { + for (CommonUploadMultiParam.NormalParam normalParam : normalParams) { + request.form(normalParam.getName(), new StringBody(normalParam.getValue(), ContentType.create("multipart/form-data", Consts.UTF_8))); + } + } + + CommonUploadParam uploadParam = param.getUploadParam(); + if (uploadParam != null) { + request.form(uploadParam.getName(), new CommonUploadParamToUploadableAdapter(uploadParam.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 { + + 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(); + } + } +} + diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorOkHttpImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorOkHttpImpl.java new file mode 100644 index 000000000..ba64bbf6d --- /dev/null +++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorOkHttpImpl.java @@ -0,0 +1,104 @@ +package me.chanjar.weixin.open.executor; + +import lombok.AllArgsConstructor; +import me.chanjar.weixin.common.bean.CommonUploadData; +import me.chanjar.weixin.open.bean.CommonUploadMultiParam; +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 org.springframework.util.CollectionUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +/** + * @author xzh + * @Description + * @createTime 2024/08/14 16:48 + */ +public class CommonUploadMultiRequestExecutorOkHttpImpl extends CommonUploadMultiRequestExecutor { + + public CommonUploadMultiRequestExecutorOkHttpImpl(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public String execute(String uri, CommonUploadMultiParam param, WxType wxType) throws WxErrorException, IOException { + MultipartBody.Builder builder = new MultipartBody.Builder() + .setType(MediaType.get("multipart/form-data")); + + List normalParams = param.getNormalParams(); + if (!CollectionUtils.isEmpty(normalParams)) { + for (CommonUploadMultiParam.NormalParam normalParam : normalParams) { + builder.addFormDataPart(normalParam.getName(), normalParam.getValue()); + } + } + + CommonUploadParam uploadParam = param.getUploadParam(); + if (uploadParam != null) { + RequestBody requestBody = new CommonUpdateDataToRequestBodyAdapter(uploadParam.getData()); + builder.addFormDataPart(uploadParam.getName(), uploadParam.getData().getFileName(), requestBody); + } + + Request request = new Request.Builder().url(uri).post(builder.build()).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; + } + } +}