From cd8d65c1e5378bddded25cad300f34024ba136ba Mon Sep 17 00:00:00 2001 From: jiangqs <jiangqs> Date: 星期一, 19 六月 2023 14:33:52 +0800 Subject: [PATCH] 进件管理 --- ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/WxShopUtils.java | 211 ++++++++ ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/IdCardInfo.java | 31 + ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/controller/management/MgtShopController.java | 11 ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/WxUploadUtils.java | 26 + ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/ContactInfo.java | 31 + ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/miniapp/AppHomeController.java | 3 ruoyi-modules/ruoyi-order/pom.xml | 2 ruoyi-modules/ruoyi-shop/pom.xml | 37 + ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/Certificate.java | 162 ++++++ ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/IdDocInfo.java | 29 + ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/EncryptedCertificateItem.java | 26 + ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/SubmitInfo.java | 51 ++ ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/service/shop/ShopService.java | 9 ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/PlainCertificateItem.java | 23 ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/BusinessLicenseInfo.java | 33 + ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/service/impl/shop/ShopServiceImpl.java | 15 ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/miniapp/AppGoodsController.java | 5 ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/AccountInfo.java | 35 + ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/dto/MgtShopAuthDto.java | 143 +++++ ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/OrganizationCertInfo.java | 27 + ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/CertificateItem.java | 22 ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/SalesSceneInfo.java | 29 + ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/SignUtils.java | 160 ++++++ ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/vo/MgtShopAuthGetVo.java | 152 ++++++ ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/CertificateUtils.java | 106 ++++ ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/pojo/shop/ShopAuthentication.java | 17 26 files changed, 1,385 insertions(+), 11 deletions(-) diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/miniapp/AppGoodsController.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/miniapp/AppGoodsController.java index baff41c..8d85168 100644 --- a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/miniapp/AppGoodsController.java +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/miniapp/AppGoodsController.java @@ -1,7 +1,6 @@ package com.ruoyi.goods.controller.miniapp; import com.ruoyi.common.core.domain.R; -import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.web.controller.BaseController; import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.goods.domain.dto.AppGoodsInfoGetDto; @@ -11,7 +10,6 @@ import com.ruoyi.goods.domain.vo.AppShoppingCartVo; import com.ruoyi.goods.service.goods.GoodsService; import com.ruoyi.goods.service.goods.ShoppingCartService; -import com.ruoyi.system.api.constant.AppErrorConstant; import com.ruoyi.system.api.domain.dto.AppBaseBathDto; import com.ruoyi.system.api.domain.poji.member.Member; import com.ruoyi.system.api.service.RemoteMemberService; @@ -59,7 +57,8 @@ } } if(appGoodsInfoGetDto.getShopId()==null){ - throw new ServiceException(AppErrorConstant.NO_POSITION); + //throw new ServiceException(AppErrorConstant.NO_POSITION); + appGoodsInfoGetDto.setShopId(1L); } AppGoodsInfoVo appGoodsInfoVo = goodsService.getGoodsInfo(appGoodsInfoGetDto); return R.ok(appGoodsInfoVo); diff --git a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/miniapp/AppHomeController.java b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/miniapp/AppHomeController.java index 0dbf3bf..b6e8f78 100644 --- a/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/miniapp/AppHomeController.java +++ b/ruoyi-modules/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/miniapp/AppHomeController.java @@ -59,7 +59,8 @@ shopId = appRecommendGoodsPageDto.getPositionShopId(); } if(shopId==null){ - throw new ServiceException(AppErrorConstant.NO_POSITION); + //throw new ServiceException(AppErrorConstant.NO_POSITION); + shopId = 1L; } Page<AppSimpleGoodsVo> page = new Page<>(); page.setSize(appRecommendGoodsPageDto.getPageSize()); diff --git a/ruoyi-modules/ruoyi-order/pom.xml b/ruoyi-modules/ruoyi-order/pom.xml index 1ce45fc..e6f5721 100644 --- a/ruoyi-modules/ruoyi-order/pom.xml +++ b/ruoyi-modules/ruoyi-order/pom.xml @@ -104,7 +104,7 @@ <dependency> <groupId>com.github.wechatpay-apiv3</groupId> <artifactId>wechatpay-java</artifactId> - <version>0.2.7</version> + <version>0.2.8</version> </dependency> </dependencies> diff --git a/ruoyi-modules/ruoyi-shop/pom.xml b/ruoyi-modules/ruoyi-shop/pom.xml index c612cf9..0a4ab38 100644 --- a/ruoyi-modules/ruoyi-shop/pom.xml +++ b/ruoyi-modules/ruoyi-shop/pom.xml @@ -102,7 +102,42 @@ <version>2.3.3</version> </dependency> - + <!-- 微信 --> + <dependency> + <groupId>com.github.wechatpay-apiv3</groupId> + <artifactId>wechatpay-apache-httpclient</artifactId> + <version>0.4.9</version> + </dependency> + <dependency> + <groupId>com.github.wechatpay-apiv3</groupId> + <artifactId>wechatpay-java</artifactId> + <version>0.2.8</version> + </dependency> + <dependency> + <groupId>com.github.javen205</groupId> + <artifactId>IJPay-WxPay</artifactId> + <version>2.9.7-17</version> + </dependency> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-rs-client</artifactId> + <version>4.0.2</version> + </dependency> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-transports-http</artifactId> + <version>4.0.2</version> + </dependency> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-frontend-jaxrs</artifactId> + <version>4.0.2</version> + </dependency> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-rs-extension-providers</artifactId> + <version>4.0.2</version> + </dependency> </dependencies> <build> diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/controller/management/MgtShopController.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/controller/management/MgtShopController.java index 22ac099..2ec080a 100644 --- a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/controller/management/MgtShopController.java +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/controller/management/MgtShopController.java @@ -169,7 +169,7 @@ } @RequestMapping(value = "/mgtAuditShopCertificate", method = RequestMethod.POST) - @ApiOperation(value = "平台编辑会员建议标签") + @ApiOperation(value = "平台审核商户证书") public R mgtAuditShopCertificate(@RequestBody MgtAuditShopCertificateDto mgtAuditShopCertificateDto) { Long userId = SecurityUtils.getUserId(); mgtAuditShopCertificateDto.setUserId(userId); @@ -196,4 +196,13 @@ List<MgtShopAuthPageVo> mgtShopAuthPageVoList = shopService.pageMgtShopAuth(page,mgtShopAuthPageDto); return R.ok(page.setRecords(mgtShopAuthPageVoList)); } + + @RequestMapping(value = "/mgtShopAuth", method = RequestMethod.POST) + @ApiOperation(value = "平台商户进件") + public R mgtShopAuth(@RequestBody MgtShopAuthDto mgtShopAuthDto) { + Long userId = SecurityUtils.getUserId(); + mgtShopAuthDto.setUserId(userId); + shopService.mgtShopAuth(mgtShopAuthDto); + return R.ok(); + } } diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/dto/MgtShopAuthDto.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/dto/MgtShopAuthDto.java new file mode 100644 index 0000000..2577bd0 --- /dev/null +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/dto/MgtShopAuthDto.java @@ -0,0 +1,143 @@ +package com.ruoyi.shop.domain.dto; + +import com.ruoyi.system.api.domain.dto.MgtBaseDto; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @ClassName Mgt + * @Description TODO + * @Author jqs + * @Date 2023/6/19 10:57 + * @Version 1.0 + */ +@Data +public class MgtShopAuthDto extends MgtBaseDto { + + @ApiModelProperty(value = "审核id") + private String authId; + /** + * 商户id + */ + @ApiModelProperty(value = "商户id") + private Long shopId; + + @ApiModelProperty(value = "商户名称") + private String shopName; + + @ApiModelProperty("店主姓名") + private String shopownerName; + + @ApiModelProperty("店主联系方式") + private String shopownerPhone; + + /** + * 主题类型1个人2企业 + */ + @ApiModelProperty(value = "主题类型1个人2企业") + private Integer mainType; + /** + * 营业执照商户名称 + */ + @ApiModelProperty(value = "营业执照商户名称") + private String blShopName; + /** + * 营业执照编号 + */ + @ApiModelProperty(value = "营业执照编号") + private String blNumber; + /** + * 营业执照法人姓名 + */ + @ApiModelProperty(value = "营业执照法人姓名") + private String blCorporateName; + /** + * 营业执照注册地址 + */ + @ApiModelProperty(value = "营业执照注册地址") + private String blRegisteredAddress; + /** + * 营业执照期限 + */ + @ApiModelProperty(value = "营业执照期限") + private String blBusinessDeanline; + /** + * 营业执照图片 + */ + @ApiModelProperty(value = "营业执照图片") + private String blImage; + /** + * 法人姓名 + */ + @ApiModelProperty(value = "法人姓名") + private String lpCorporateName; + /** + * 法人身份证号 + */ + @ApiModelProperty(value = "法人身份证号") + private String lpIdCard; + /** + * 法人身份证开始日期 + */ + @ApiModelProperty(value = "法人身份证开始日期") + private String lpIcStartDate; + /** + * 法人身份证有效日期 + */ + @ApiModelProperty(value = "法人身份证有效日期") + private String lpIcEndDate; + /** + * 法人身份证正面 + */ + @ApiModelProperty(value = "法人身份证正面") + private String lpIcFront; + /** + * 法人身份证背面 + */ + @ApiModelProperty(value = "法人身份证背面") + private String lpIcBack; + /** + * 结算账户类型1对公2对私 + */ + @ApiModelProperty(value = "结算账户类型1对公2对私") + private String settlementAccountType; + /** + * 开户行 + */ + @ApiModelProperty(value = "开户行") + private String saBank; + /** + * 开户名称 + */ + @ApiModelProperty(value = "开户名称") + private String saAccountName; + /** + * 开户所在省 + */ + @ApiModelProperty(value = "开户所在省") + private String saBankProvinceCode; + /** + * 开户所在市 + */ + @ApiModelProperty(value = "开户所在市") + private String saBankCityCode; + /** + * 开户行全称 + */ + @ApiModelProperty(value = "开户行全称") + private String saBankName; + /** + * 银行卡号 + */ + @ApiModelProperty(value = "银行卡号") + private String saNumber; + + @ApiModelProperty(value = "补充资料") + private String baPics; + + @ApiModelProperty(value = "补充说明") + private String baDesc; + + + +} diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/pojo/shop/ShopAuthentication.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/pojo/shop/ShopAuthentication.java index 898c107..f6ef0d7 100644 --- a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/pojo/shop/ShopAuthentication.java +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/pojo/shop/ShopAuthentication.java @@ -242,9 +242,9 @@ private String adRejectReason; /** * 法人验证链接 -1、当申请状态为 -ACCOUNT_NEED_VERIFY,且通过系统校验的申请单,将返回链接。 -2、建议将链接转为二维码展示,让商户法人用微信扫码打开,完成账户验证。 + 1、当申请状态为 + ACCOUNT_NEED_VERIFY,且通过系统校验的申请单,将返回链接。 + 2、建议将链接转为二维码展示,让商户法人用微信扫码打开,完成账户验证。 */ @TableField("legal_validation_url") private String legalValidationUrl; @@ -252,7 +252,16 @@ private Date createTime; @TableField("update_time") private Date updateTime; - + /** + * 补充资料 + */ + @TableField("ba_pics") + private String baPics; + /** + * 补充说明 + */ + @TableField("ba_desc") + private String baDesc; @Override protected Serializable pkVal() { diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/vo/MgtShopAuthGetVo.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/vo/MgtShopAuthGetVo.java new file mode 100644 index 0000000..e14408f --- /dev/null +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/domain/vo/MgtShopAuthGetVo.java @@ -0,0 +1,152 @@ +package com.ruoyi.shop.domain.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @ClassName MgtShopAuthDto + * @Description TODO + * @Author jqs + * @Date 2023/6/19 10:21 + * @Version 1.0 + */ +@Data +public class MgtShopAuthGetVo { + + @ApiModelProperty(value = "审核id") + private String authId; + /** + * 商户id + */ + @ApiModelProperty(value = "商户id") + private Long shopId; + + @ApiModelProperty(value = "商户名称") + private String shopName; + + @ApiModelProperty("店主姓名") + private String shopownerName; + + @ApiModelProperty("店主联系方式") + private String shopownerPhone; + + /** + * 审核状态 + 1:CHECKING:资料校验中 + 2:ACCOUNT_NEED_VERIFY:待账户验证 + 3:AUDITING:审核中 + 4:REJECTED:已驳回 + 5:NEED_SIGN:待签约 + 6:FINISH:完成 + 7:FROZEN:已冻结 + 8:CANCELED:已作废 + */ + @ApiModelProperty(value = "审核状态") + private Integer auditStatus; + /** + * 主题类型1个人2企业 + */ + @ApiModelProperty(value = "主题类型1个人2企业") + private Integer mainType; + /** + * 营业执照商户名称 + */ + @ApiModelProperty(value = "营业执照商户名称") + private String blShopName; + /** + * 营业执照编号 + */ + @ApiModelProperty(value = "营业执照编号") + private String blNumber; + /** + * 营业执照法人姓名 + */ + @ApiModelProperty(value = "营业执照法人姓名") + private String blCorporateName; + /** + * 营业执照注册地址 + */ + @ApiModelProperty(value = "营业执照注册地址") + private String blRegisteredAddress; + /** + * 营业执照期限 + */ + @ApiModelProperty(value = "营业执照期限") + private String blBusinessDeanline; + /** + * 营业执照图片 + */ + @ApiModelProperty(value = "营业执照图片") + private String blImage; + /** + * 法人姓名 + */ + @ApiModelProperty(value = "法人姓名") + private String lpCorporateName; + /** + * 法人身份证号 + */ + @ApiModelProperty(value = "法人身份证号") + private String lpIdCard; + /** + * 法人身份证开始日期 + */ + @ApiModelProperty(value = "法人身份证开始日期") + private String lpIcStartDate; + /** + * 法人身份证有效日期 + */ + @ApiModelProperty(value = "法人身份证有效日期") + private String lpIcEndDate; + /** + * 法人身份证正面 + */ + @ApiModelProperty(value = "法人身份证正面") + private String lpIcFront; + /** + * 法人身份证背面 + */ + @ApiModelProperty(value = "法人身份证背面") + private String lpIcBack; + /** + * 结算账户类型1对公2对私 + */ + @ApiModelProperty(value = "结算账户类型1对公2对私") + private String settlementAccountType; + /** + * 开户行 + */ + @ApiModelProperty(value = "开户行") + private String saBank; + /** + * 开户名称 + */ + @ApiModelProperty(value = "开户名称") + private String saAccountName; + /** + * 开户所在省 + */ + @ApiModelProperty(value = "开户所在省") + private String saBankProvinceCode; + /** + * 开户所在市 + */ + @ApiModelProperty(value = "开户所在市") + private String saBankCityCode; + /** + * 开户行全称 + */ + @ApiModelProperty(value = "开户行全称") + private String saBankName; + /** + * 银行卡号 + */ + @ApiModelProperty(value = "银行卡号") + private String saNumber; + + @ApiModelProperty(value = "补充资料") + private String baPics; + + @ApiModelProperty(value = "补充说明") + private String baDesc; +} diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/service/impl/shop/ShopServiceImpl.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/service/impl/shop/ShopServiceImpl.java index 4a39190..55a9409 100644 --- a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/service/impl/shop/ShopServiceImpl.java +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/service/impl/shop/ShopServiceImpl.java @@ -614,4 +614,19 @@ MgtBulletinBoardVo mgtBulletinBoardVoShop = shopMapper.shopTotal(); return mgtBulletinBoardVoShop; } + + /** + * @description 商户进件 + * @author jqs + * @date 2023/6/19 11:02 + * @param mgtShopAuthDto + * @return void + */ + @Override + public void mgtShopAuth(MgtShopAuthDto mgtShopAuthDto){ + ShopAuthentication shopAuthentication = shopAuthenticationService.getById(mgtShopAuthDto.getAuthId()); + BeanUtils.copyProperties(mgtShopAuthDto , shopAuthentication); + shopAuthentication.setAuditStatus(3); + shopAuthenticationService.saveOrUpdate(shopAuthentication); + } } diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/service/shop/ShopService.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/service/shop/ShopService.java index 4674c34..2fcc55c 100644 --- a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/service/shop/ShopService.java +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/service/shop/ShopService.java @@ -169,4 +169,13 @@ * @date 2023/6/18 17:01 */ MgtBulletinBoardVo boardShopTotal(); + + /** + * @description 商户进件 + * @author jqs + * @date 2023/6/19 11:02 + * @param mgtShopAuthDto + * @return void + */ + void mgtShopAuth(MgtShopAuthDto mgtShopAuthDto); } diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/Certificate.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/Certificate.java new file mode 100644 index 0000000..0c917e3 --- /dev/null +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/Certificate.java @@ -0,0 +1,162 @@ +package com.ruoyi.shop.util; + +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.ruoyi.shop.util.dto.CertificateItem; +import com.ruoyi.shop.util.dto.EncryptedCertificateItem; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; + +/** + * @date 2020-03-18 15:06 + * @description + */ +@Slf4j +public class Certificate { + + private static final Logger logger = LoggerFactory.getLogger(Certificate.class); + + /** + * 获取微信支付平台证书 + * + * @param merchantId + * @param timeout + * @param serialNo + * @param mchPrivateKeyPath + * @param APIv3Key + * @param savePath + * @return + */ + public static List<X509Certificate> getCertByAPI(String merchantId, int timeout, String serialNo, String mchPrivateKeyPath, String wechatPubKeyPath, String APIv3Key, String savePath) { + String result = ""; + //创建http请求 + HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/certificates"); + httpGet.addHeader("Content-Type", "application/json"); + httpGet.addHeader("Accept", "application/json"); + + String authorization = SignUtils.authorization("GET", "/v3/certificates", merchantId, serialNo, "", mchPrivateKeyPath); + + //设置认证信息 + httpGet.setHeader("Authorization", authorization); + + //设置请求器配置:如超时限制等 + RequestConfig config = RequestConfig.custom().setSocketTimeout(timeout * 1000).setConnectTimeout(timeout * 1000).build(); + httpGet.setConfig(config); + List<X509Certificate> x509Certs = new ArrayList<X509Certificate>(); + try { + CloseableHttpClient httpClient = HttpClients.createDefault(); + CloseableHttpResponse response = httpClient.execute(httpGet); + int statusCode = response.getStatusLine().getStatusCode(); + HttpEntity httpEntity = response.getEntity(); + result = EntityUtils.toString(httpEntity, "UTF-8"); + if (statusCode == 200) { + logger.info("下载平台证书返回结果:" + result); + Header[] timestampHeader = response.getHeaders("Wechatpay-Timestamp"); + Header[] nonceHeader = response.getHeaders("Wechatpay-Nonce"); + Header[] signatureHeader = response.getHeaders("Wechatpay-Signature"); + if (timestampHeader != null && timestampHeader.length > 0 && + nonceHeader != null && nonceHeader.length > 0 && + signatureHeader != null && signatureHeader.length > 0) { + // 验证微信支付返回签名 + String wTimestamp = timestampHeader[0].getValue(); + String wNonce = nonceHeader[0].getValue(); + String wSign = signatureHeader[0].getValue(); + + logger.info("wTimestamp:{},wNonce:{},wSign:{}", wTimestamp, wNonce, wSign); + // 拼装待签名串 + StringBuffer ss = new StringBuffer(); + ss.append(wTimestamp).append("\n"); + ss.append(wNonce).append("\n"); + ss.append(result).append("\n"); + // 验证签名 + if (SignUtils.v3VerifyRSA(ss.toString(), Base64.decodeBase64(wSign.getBytes()), wechatPubKeyPath)) { + List<CertificateItem> certList = new ArrayList<CertificateItem>(); + JSONObject json = JSONObject.parseObject(result); + logger.info("查询结果json字符串转证书List:" + json.get("data")); + JSONArray jsonArray = (JSONArray) json.get("data"); + for (int i = 0; i < jsonArray.size(); i++) { + CertificateItem certificateItem = new CertificateItem(); + EncryptedCertificateItem encryptCertificate = new EncryptedCertificateItem(); + JSONObject bo = JSONObject.parseObject(jsonArray.get(i).toString()); + certificateItem.setSerial_no(bo.get("serial_no").toString()); + certificateItem.setEffective_time(bo.get("effective_time").toString()); + certificateItem.setExpire_time(bo.get("expire_time").toString()); + JSONObject encryptBo = JSONObject.parseObject(bo.get("encrypt_certificate").toString()); + encryptCertificate.setAlgorithm(encryptBo.get("algorithm").toString()); + encryptCertificate.setNonce(encryptBo.get("nonce").toString()); + encryptCertificate.setAssociated_data(encryptBo.get("associated_data").toString()); + encryptCertificate.setCiphertext(encryptBo.get("ciphertext").toString()); + certificateItem.setEncrypt_certificate(encryptCertificate); + certList.add(certificateItem); + } + logger.info("证书List:" + certList); + + /*List<PlainCertificateItem> plainList = decrypt(certList, APIv3Key); + if (CollectionUtils.isNotEmpty(plainList)) { + logger.info("平台证书开始保存"); + x509Certs = saveCertificate(plainList, savePath); + }*/ + } + } + } + response.close(); + httpClient.close(); //throw + return x509Certs; + } catch (Exception e) { + e.printStackTrace(); + logger.error("下载平台证书返回结果:" + e); + } + return x509Certs; + } + + + /*private static List<PlainCertificateItem> decrypt(List<CertificateItem> certList,CloseableHttpResponse response) throws GeneralSecurityException, IOException { + List<PlainCertificateItem> plainCertificateList = new ArrayList<PlainCertificateItem>(); + AesUtil aesUtil = new AesUtil("".getBytes(StandardCharsets.UTF_8)); + for(CertificateItem item:certList){ + PlainCertificateItem bo = new PlainCertificateItem(); + bo.setSerialNo(item.getSerial_no()); + bo.setEffectiveTime(item.getEffective_time()); + bo.setExpireTime(item.getExpire_time()); + logger.info("平台证书密文解密"); + bo.setPlainCertificate(aesUtil.decryptToString(item.getEncrypt_certificate().getAssociated_data().getBytes(StandardCharsets.UTF_8), + item.getEncrypt_certificate().getNonce().getBytes(StandardCharsets.UTF_8), item.getEncrypt_certificate().getCiphertext())); + logger.info("平台证书公钥明文:"+bo.getPlainCertificate()); + plainCertificateList.add(bo); + } + return plainCertificateList; + }*/ + + + //证书保存 + /*private static List<X509Certificate> saveCertificate(List<PlainCertificateItem> cert) throws IOException { + List<X509Certificate> x509Certs = new ArrayList<X509Certificate>(); + File file = new File("平台证书路径"); + file.mkdirs(); + for (PlainCertificateItem item : cert) { + ByteArrayInputStream inputStream = new ByteArrayInputStream(item.getPlainCertificate().getBytes(StandardCharsets.UTF_8)); + X509Certificate x509Cert = PemUtil.loadCertificate(inputStream); + x509Certs.add(x509Cert); + String outputAbsoluteFilename = file.getAbsolutePath() + File.separator + "wechatpay_" + item.getSerialNo() + ".pem"; + try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputAbsoluteFilename), StandardCharsets.UTF_8))) { + writer.write(item.getPlainCertificate()); + } + logger.info("输出证书文件目录:" + outputAbsoluteFilename); + } + return x509Certs; + }*/ +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/CertificateUtils.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/CertificateUtils.java new file mode 100644 index 0000000..3e24f6e --- /dev/null +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/CertificateUtils.java @@ -0,0 +1,106 @@ +package com.ruoyi.shop.util; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.io.FileUtil; +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.cert.*; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; + + +/** + * @date 2020-03-18 11:25 + * @description 证书相关 + */ +public class CertificateUtils { + + + /** + * 获取商户私钥 + * @param priKeyPath 商户私钥证书路径 + * @return + */ + public static String getPrivateKey(String priKeyPath) throws Exception { + String originalKey = FileUtil.readUtf8String(priKeyPath); + String privateKey = originalKey + .replace("-----BEGIN PRIVATE KEY-----", "") + .replace("-----END PRIVATE KEY-----", "") + .replaceAll("\\s+", ""); + return getPrivateKeyStr(loadPrivateKey(privateKey)); + } + + + private static String getPrivateKeyStr(PrivateKey privateKey) { + return Base64.encode(privateKey.getEncoded()); + } + + + /** + * 从字符串中加载私钥 + * @param privateKeyStr 私钥 + * @return + */ + public static PrivateKey loadPrivateKey(String privateKeyStr) throws Exception { + try { + byte[] buffer = Base64.decode(privateKeyStr); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return keyFactory.generatePrivate(keySpec); + } catch (NoSuchAlgorithmException e) { + throw new Exception("无此算法"); + } catch (InvalidKeySpecException e) { + throw new Exception("私钥非法"); + } catch (NullPointerException e) { + throw new Exception("私钥数据为空"); + } + } + + + /** + * 获取证书 + * @param fileName 证书文件路径 (required) + * @return + */ + public static X509Certificate getCertificate(String fileName) throws IOException { + InputStream fis = new FileInputStream(fileName); + try (BufferedInputStream bis = new BufferedInputStream(fis)) { + CertificateFactory cf = CertificateFactory.getInstance("X509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(bis); + cert.checkValidity(); + return cert; + } catch (CertificateExpiredException e) { + throw new RuntimeException("证书已过期", e); + } catch (CertificateNotYetValidException e) { + throw new RuntimeException("证书尚未生效", e); + } catch (CertificateException e) { + throw new RuntimeException("无效的证书文件", e); + } + } + + + /** + * 获取证书 + * @param inputStream 证书文件 + * @return + */ + public static X509Certificate getCertificate(InputStream inputStream) { + try { + CertificateFactory cf = CertificateFactory.getInstance("X509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream); + cert.checkValidity(); + return cert; + } catch (CertificateExpiredException e) { + throw new RuntimeException("证书已过期", e); + } catch (CertificateNotYetValidException e) { + throw new RuntimeException("证书尚未生效", e); + } catch (CertificateException e) { + throw new RuntimeException("无效的证书", e); + } + } +} diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/SignUtils.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/SignUtils.java new file mode 100644 index 0000000..b61ba47 --- /dev/null +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/SignUtils.java @@ -0,0 +1,160 @@ +package com.ruoyi.shop.util; + +import cn.hutool.http.HttpResponse; +import com.ruoyi.common.core.utils.uuid.IdUtils; +import com.wechat.pay.contrib.apache.httpclient.util.PemUtil; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.FileInputStream; +import java.nio.charset.StandardCharsets; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.List; +import java.util.Map; + +/** + * @date 2020-03-18 11:02 + * @description 签名相关 + */ +public class SignUtils { + private static final Logger logger = LoggerFactory.getLogger(SignUtils.class); + + /** + * 签名生成 + * @param method 请求方法 如POST + * @param urlSuffix 请求地址后缀 如/v3/certificates + * @param mchId 电商平台商户号 + * @param serialNo 电商平台商户API证书序列号 + * @param body 请求请求报文主体,如果没有,就传空字符串 + * @param mchPrivateKeyPath 电商平台商户API私钥 + * @return + */ + public static String authorization(String method,String urlSuffix,String mchId,String serialNo,String body,String mchPrivateKeyPath) { + try { + String mchPrivateKey = CertificateUtils.getPrivateKey(mchPrivateKeyPath); + //时间戳 + String timestamp = Long.toString(System.currentTimeMillis()/1000); + //随机数 + String nonceStr = IdUtils.randomUUID(); + + //拼签名串 + StringBuilder sb = signMessage(method,urlSuffix,timestamp,nonceStr,body); + + logger.info("sign original string:{}",sb.toString()); + + //计算签名 + String sign = new String(Base64.encodeBase64(v3signRSA(sb.toString(),mchPrivateKey))); + + logger.info("sign result:{}",sign); + + //拼装http头的Authorization内容 + String authorization ="WECHATPAY2-SHA256-RSA2048 mchid=\""+mchId+"\",nonce_str=\""+nonceStr+"\",signature=\""+sign+"\",timestamp=\""+timestamp+"\",serial_no=\""+serialNo+"\""; + + logger.info("authorization result:{}",authorization); + + return authorization; + + } catch (Exception e) { + logger.error("authorization Exception result:{}",e); + e.printStackTrace(); + return null; + } + } + + /** + * Authorization 签名串 + * @param method + * @param urlSuffix + * @param timestamp + * @param nonceStr + * @param body + * @return + */ + private static StringBuilder signMessage(String method,String urlSuffix,String timestamp,String nonceStr,String body) { + return new StringBuilder() + .append(method) + .append("\n") + .append(urlSuffix) + .append("\n") + .append(timestamp) + .append("\n") + .append(nonceStr) + .append("\n") + .append(body) + .append("\n"); + } + + /** + * 私钥签名 + * @param data 需要加密的数据 + * @param mchPriKey + * @return + * @throws Exception + */ + public static byte[] v3signRSA(String data, String mchPriKey) throws Exception { + //签名的类型 + Signature sign = Signature.getInstance("SHA256withRSA"); + //读取商户私钥,该方法传入商户私钥证书的内容即可 + byte[] keyBytes = Base64.decodeBase64(mchPriKey); + PKCS8EncodedKeySpec keySpec =new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PrivateKey priKey = keyFactory.generatePrivate(keySpec); + sign.initSign(priKey); + sign.update(data.getBytes(StandardCharsets.UTF_8)); + return sign.sign(); + } + + public static boolean v3VerifyRSA(HttpResponse response,String wechatPubKeyPath) { + + if (response == null || StringUtils.isEmpty(wechatPubKeyPath)) { + return false; + } + Map<String, List<String>> headers = response.headers(); + //验证微信支付返回签名 + String headsTimestamp = headers.get("Wechatpay-Timestamp").get(0); + String headsNonce = headers.get("Wechatpay-Nonce").get(0); + String headsSign = headers.get("Wechatpay-Signature").get(0); + String resContent = response.body(); + //拼装待签名串 + StringBuilder sb =new StringBuilder(); + sb.append(headsTimestamp).append("\n"); + sb.append(headsNonce).append("\n"); + sb.append(resContent).append("\n"); + try { + //验证签名 + return v3VerifyRSA(sb.toString(), Base64.decodeBase64(headsSign.getBytes()), wechatPubKeyPath); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + public static boolean v3VerifyRSA(String data,byte[] sign, String wechatPubKeyPath) throws Exception{ + if(data == null || sign == null || wechatPubKeyPath == null){ + return false; + } + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + FileInputStream in =new FileInputStream(wechatPubKeyPath); + Certificate c = cf.generateCertificate(in); + in.close(); + PublicKey publicKey = c.getPublicKey(); + Signature signature = Signature.getInstance("SHA256WithRSA"); + signature.initVerify(publicKey); + signature.update(data.getBytes(StandardCharsets.UTF_8)); + + boolean result = signature.verify(sign); + if (result) { + logger.info("v3VerifyRSA result:{}","签名验证成功"); + } else { + logger.info("v3VerifyRSA result:{}","签名验证失败"); + } + return result; + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/WxShopUtils.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/WxShopUtils.java new file mode 100644 index 0000000..97e9a57 --- /dev/null +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/WxShopUtils.java @@ -0,0 +1,211 @@ +package com.ruoyi.shop.util; + +import com.alibaba.fastjson2.JSONObject; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.shop.util.dto.ContactInfo; +import com.ruoyi.shop.util.dto.IdCardInfo; +import com.ruoyi.shop.util.dto.SubmitInfo; +import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder; +import com.wechat.pay.contrib.apache.httpclient.auth.*; +import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager; +import com.wechat.pay.contrib.apache.httpclient.exception.HttpCodeException; +import com.wechat.pay.contrib.apache.httpclient.exception.NotFoundException; +import com.wechat.pay.contrib.apache.httpclient.util.PemUtil; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.util.EntityUtils; + +import javax.crypto.Cipher; +import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Base64; + +/** + * @ClassName WxShopUtils + * @Description TODO + * @Author jqs + * @Date 2023/6/19 11:11 + * @Version 1.0 + */ + +public class WxShopUtils { + + public void ApplymentSubMch() throws Exception { + + // 初始化httpClient + CloseableHttpClient httpClient = createHttpClient(); + //请求URL + HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/"); + // 请求body参数 + String reqdata = "{" + + "\"business_info\": {" + + "\"merchant_shortname\":\"上海XXX有限公司\"," + + "\"service_phone\":\"139XXXX\"," + + "\"sales_info\": {" + + "\"mini_program_info\": {" + + "\"mini_program_pics\": [" + + "\"0\":\"F8O5MNAOlYZyxZcLnWXkyk72coZ3CVX3XobPZng-xepKPTrcH_XMfrGGYLi1XFogMG9P25LSUX6gjXU5iPI74YqiRUDfORyw2d76wK3vzuQ\"" + + "]," + + "\"mini_program_sub_appid\":\"wx76c3f74c108876c2\"" + + "}," + + "\"mp_info\": {" + + "\"mp_pics\": [" + + "\"0\":\"F8O5MNAOlYZyxZcLnWXkys5TBxf0dyfesnyfNuquBMArHRfgCq8hDRdscDpblCcEgvgV5MkVch9IBEX7aatZCmI8k5Wdb_M8a4bYcmlg6V8\"" + + "]," + + "\"mp_sub_appid\":\"wx85c88c63bd22651f\"" + + "}," + + "\"sales_scenes_type\": [" + + "\"0\":\"SALES_SCENES_MP\"," + + "\"1\":\"SALES_SCENES_MINI_PROGRAM\"" + + "]" + + "}" + + "}," + + "\"subject_info\": {" + + "\"business_license_info\": {" + + "\"legal_person\":\"江XX\"," + + "\"license_copy\":\"F8O5MNAOlYZyxZcLnWXkysZ5xo8fE3SHJ1pHUe6OJKmNIWtqUVyv4aY2-JLTgjDOSovWaKkBu3AbkjGuQXhesDzREu2pT_Yf_hxlFKPJMwQ\"," + + "\"merchant_name\":\"上海XXX有限公司\"," + + "\"license_number\":\"91310118MA1JXXXX\"" + + "}," + + "\"subject_type\":\"SUBJECT_TYPE_ENTERPRISE\"," + + "\"identity_info\": {" + + "\"owner\":true," + + "\"id_doc_type\":\"IDENTIFICATION_TYPE_IDCARD\"," + + "\"id_card_info\": {" + + "\"id_card_copy\":\"F8O5MNAOlYZyxZcLnWXkyvLpqoz7MNRULxju0NqUCtLGBl_vm8Bhj9uAyuLyDART9UsA10spF9gbT3DEoM85HxPQOhMuilK0zLtOxAjPx58\"," + + "\"card_period_end\":\"2035-12-28\"," + + "\"card_period_begin\":\"2015-12-28\"," + + "\"id_card_name\":\"JRMJGA7B7oSVS+krFeaQn4AvYZE2LL9tTwA+XXa9lYJU4AhS+Qheb7fhgo+D+hfa0v+ykU1BVvVo7NpCfgOYQqmYDyYF27Q/p4hB7IoqZLhJUE+hTG45VNoa9ASaKG79Hg+eGz4YTIHFGMFm1ljyg4fd5lGJixCqn38/gCfwm5x6vDOMVkFpqbUdR7klQwReGoG7iSlEpr4gZPqzItcBHiuXidMToKZTX1Lol1Lx52DHk0blcdh1CMRhv+wxQzF0lJMy/WtVyjKuB8daDbLJKTEwDx5KfkTZGHmGiaJnWY0qFX03sXsufvfB0Wj6Z37+nJnV16fplPmdr1/KEHamLw==\"," + + "\"id_card_national\":\"F8O5MNAOlYZyxZcLnWXkyvcmQrkBXCIo2vZGUoM6ER-skL5k6IOhzeJ34tNNUggQIPfJbM_pzdg9jM4pQbkIm84_bKfi2JKNn99xIurNgwI\"," + + "\"id_card_number\":\"V0quwnIu/PLbdQQ3/nzMqjvHtChDqed4Jpc3Iy2lgnFoWVNXguRWBHMYKHaLgLvnxLvO6TciMnrSw13QzUJD4ZnEIiks8gGTd+OCzl5Jl3F+sneQ+Js4akBnCSBQso/SERvi6vUqCeRhX1vtiFsmKtqlL8r/ssrFev4FoJEka5gGME1osTgcpMMTIR8rolIO1oXbl3e8z5RDics5xKH2Ogjzis73yq9M18ap0uRRdLWoX/cxeG3tbU1bi5jZsAU9hGHXs4BKTaHfrslsKIkqXR0f2Jpk7H5qtwAyP8glcALN7gB5DIOmBEIZ5zx2PrDm38CsZHstu0hF8beXV/PG2w==\"" + + "}" + + "}" + + "}," + + "\"business_code\":\"20201126100507000003\"," + + "\"contact_info\": {" + + "\"contact_name\":\"AD2jwe8eYFYfeoSmBpyRYUawyQgQkUoAajOlHnQM/JzproDF7hikLDouMr5Mb1W5otvdJZYEipG0HzwLpG9NXbqP6SXSpzQFb8fY5cpuXZsIbDy70lAybF0bbxJiJw1PHSd7KpMbu0XHqwlicePLUOw7HCNV6euQsKEvtusiWsaVrNNdKXpj3ONhyAg2ws4ibc56GUVoNll3osmGLPi6/bIn3pD6sjNThgPE9UzRQax0XPwgIpafIewQiVy0GNtv5P33wqPa9pAsdEmaLXNtQr2Ddjw5SYMInen1qbVO8NP0VhuWmYiAjd1WbkNnR+gbwsilBCYYeRuFbKfqatASnA==\"," + + "\"mobile_phone\":\"GLc5+TuqJbxLeQO+CrKeDWF+7lZq9IsidIU4zcMpus4qsE8r1qNyvVMjrZfWLrjOItiQhXqkiKZs0B4M0UWAviWwmBhNWW0BJrauBjZbGZU+pLHC/2eOetdDC4sQqHN7Xw0N4tizqeQNu49n+DbSiv0TL09EcmNUUV9rImfjpVyo77MxKhPvdg3ODwS+IVvY2Tc9q11iBgaPIQ+XwoBaJGth1wdw0GLgEFUmX02TWxjHxq7f5O1RU3LjBlt1O+56ZZYpA+zr+IjQ/TwrIDp+4nk9v1oW2wtHuwrdqKrlLyJ1/zdoqwSddLuGxp8PwSM8CKobQP8TXhJu0S9pwLbNyg==\"," + + "\"contact_id_number\":\"iC35X6SaOx4A4BEJ4fmM2oOkYRO5rEzRh2QRdrxFD3+HwmNjxddsm1LoqfhSiV34DAO2x3Ded3q2c1LJ7NHqa3/IGCDss4FKlgIyiu5AmzQTTYwsobmvVFxeSUXA4PnH/tUTfatJOuj+9Emt7fmnpO9uWeCLIn5CXaaABrXpO4mUu8qPBaoF2jTfbwBm6QiYX58kATyRrIvBRs6VorHJydXkz3P1hCejh8sAYoJXlNHnoajI+NEwiWX9RhwUadYLbMwww68cc7Yzehp3s6an0NWuC76Y4e7FQ/i5D9ZpUvLKUoYfFsZMnHrv/PhLxmv5l8gQs9/IkmOdYfRujKZJwQ==\"," + + "\"contact_email\":\"ggK2ABtJ8bBiBo1iM7I6R2yEvhD6WC96d07gthnPGajc4lBCKpIqXjyNX8B97vc0OilyLRNUcySbT/KUejPyu4x9W6Ok6iS4zcerfKfIQkKs+3JXIMo0bu+GyI5O0fzRrPg1Mek2okfIjVK9wiTNJTzoGyz9twMXEaqqrOTbysyhnkqfrol5dad/TPg8qNWaBO3+Ma/hr1Tr0xeHWkKX3mBySC3NW49HM51x0PvFAwnStHr/8hiGzGpqAA3yJuYdlEwey3Lv+/bMmbTq+AyrYq9xX3q+n0VHuiSnzgICPwQiP4zXsoivA0bm7DSgcP1Oa6MjpGqMOS7AU1dHyak2GQ==\"" + + "}," + + "\"bank_account_info\": {" + + "\"account_number\":\"Bfu6CzrRWlVTLZwjEK2CCXG0KRfGoIsbYs9IYmtFcV9FTEVLCcVCRGW6DVE2hMMr7U9tSdo7QqsptXZ7Zhciandyx9kRkY/VmPywurySvCbqpOLbx3AgmQY7H6/Ye542R0uloi6Pdp5FjqY/TdnlDcTS4cqv9iqU0DqKAUt7q+L6jZ8lrSlGFPI/1RkXCGAhlTSZ/iAJYDWzcN/E0cno9BQPYCmEIWldzj7W3Tmhi1eaZYX5mlLWnTOuVmMsRXIehb4y6LCi6T0kS7/c3GOFwlTzHVaaUgFqZhOL00h2G4Cl94uZfuVNO7KTiFaWtV61muEN6JfaSnFwRDSHxhtsRg==\"," + + "\"bank_address_code\":\"310101\"," + + "\"account_name\":\"RVBRWZKlmzrjkDmz4uEkaLQLU5q5xErXGoWhzDNdnQjRlfn1NVHL2EtIE+B0BULFNOHrX61q13lcgo9CDal9YJ/LjZkzAAsivwJZpNSRZbAsNNjqbYiiVhdnxYpwMqtukVgZAFgx0XMovOeSGX1+Dosc2vKJSsxtUw6wJXcZbMjvsX5/xamFTvRIx1J2a/q3ODBJ9URO5O2FDhGwLx8LQnFIv7xUDM3JXw7c6+eNy1OYTVwlj3/MIDQVw2eiPjpG1vC6K6PRwCI4wFZk1QwH99Xa3Wwvf+ek54j7FQTh0N703dK6jjonL5L6Lh9ZsckLx45InkARlPnU0KQpoK5g9w==\"," + + "\"bank_account_type\":\"BANK_ACCOUNT_TYPE_CORPORATE\"," + + "\"account_bank\":\"招商银行\"" + + "}," + + "\"settlement_info\": {" + + "\"settlement_id\":\"716\"," + + "\"qualification_type\":\"零售批发/生活娱乐/网上商城/其他\"" + + "}" + + "}"; + StringEntity entity = new StringEntity(reqdata,"utf-8"); + entity.setContentType("application/json"); + httpPost.setEntity(entity); + httpPost.setHeader("Accept", "application/json"); + httpPost.setHeader("Wechatpay-Serial", "XXXXXXXXXXXXXX"); + //完成签名并执行请求 + CloseableHttpResponse response = httpClient.execute(httpPost); + + try { + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode == 200) { //处理成功 + System.out.println("success,return body = " + EntityUtils.toString(response.getEntity())); + } else if (statusCode == 204) { //处理成功,无返回Body + System.out.println("success"); + } else { + System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity())); + throw new IOException("request failed"); + } + } finally { + response.close(); + } + httpClient.close(); + } + + /** + * @description 创建httpClient + * @author jqs + * @date 2023/6/19 12:50 + * @param + * @return CloseableHttpClient + */ + private CloseableHttpClient createHttpClient() throws NotFoundException, IOException, GeneralSecurityException, HttpCodeException { + String merchantId = ""; + PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey( + new FileInputStream("/path/to/apiclient_key.pem")); + String merchantSerialNumber = ""; + String apiV3Key = ""; + + // 获取证书管理器实例 + CertificatesManager certificatesManager = CertificatesManager.getInstance(); + // 向证书管理器增加需要自动更新平台证书的商户信息 + certificatesManager.putMerchant(merchantId, new WechatPay2Credentials(merchantId, + new PrivateKeySigner(merchantSerialNumber, merchantPrivateKey)), apiV3Key.getBytes(StandardCharsets.UTF_8)); + // ... 若有多个商户号,可继续调用putMerchant添加商户信息 + + // 从证书管理器中获取verifier + Verifier verifier = certificatesManager.getVerifier(merchantId); + WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create() + .withMerchant(merchantId, merchantSerialNumber, merchantPrivateKey) + .withValidator(new WechatPay2Validator(verifier)); + + CloseableHttpClient httpClient = builder.build(); + return httpClient; + } + + //提交申请 + /*public static String apply(SubmitInfo submitInfo) throws Exception { + String bodyStr=convertToStr(submitInfo); + HttpResponse response = HttpUtils.v3HttpExecute("POST",EcommerceUrl.APPLYMENTS, + "自己系统的应用名称","服务商商户号","商户API证书序列号","平台证书序列号",requestParam,"商户API证书位置.pem",null); + }*/ + + + //加密申请信息 + private static String convertToStr(SubmitInfo submitInfo) throws Exception { + rsaEncryptSubmitInfo(submitInfo); + return JSONObject.toJSONString(submitInfo); + } + + private static void rsaEncryptSubmitInfo(SubmitInfo submitInfo) throws Exception { + IdCardInfo idCardInfo=submitInfo.getId_card_info(); + if(idCardInfo!=null){ + idCardInfo.setId_card_name(rsaEncryptByCert(idCardInfo.getId_card_name())); + idCardInfo.setId_card_number(rsaEncryptByCert(idCardInfo.getId_card_number())); + } + ContactInfo contactInfo=submitInfo.getContact_info(); + if(contactInfo!=null){ + contactInfo.setContact_name(rsaEncryptByCert(contactInfo.getContact_name())); + contactInfo.setContact_id_card_number(rsaEncryptByCert(contactInfo.getContact_id_card_number())); + contactInfo.setMobile_phone(rsaEncryptByCert(contactInfo.getMobile_phone())); + if(!StringUtils.isEmpty(contactInfo.getContact_email())){ + contactInfo.setContact_email(rsaEncryptByCert(contactInfo.getContact_email())); + } + } + } + + private static String rsaEncryptByCert(String content) throws Exception { + String platPrivateKey = ""; + InputStream inStream=new ByteArrayInputStream(platPrivateKey.getBytes(StandardCharsets.UTF_8)); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate certificate = (X509Certificate)cf.generateCertificate(inStream); + PublicKey publicKey=certificate.getPublicKey(); + Cipher ci= Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"); + ci.init(Cipher.ENCRYPT_MODE,publicKey); + return Base64.getEncoder().encodeToString(ci.doFinal(content.getBytes(StandardCharsets.UTF_8))); + } + + +} diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/WxUploadUtils.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/WxUploadUtils.java new file mode 100644 index 0000000..fb68541 --- /dev/null +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/WxUploadUtils.java @@ -0,0 +1,26 @@ +package com.ruoyi.shop.util; + +/** + * @ClassName WxUploadUtils + * @Description TODO + * @Author jqs + * @Date 2023/6/19 11:55 + * @Version 1.0 + */ +public class WxUploadUtils { + + /*String filePath = "/your/home/hellokitty.png"; + URI uri = new URI("https://api.mch.weixin.qq.com/v3/merchant/media/upload"); + File file = new File(filePath); + + + FileInputStream ins1 = new FileInputStream(file)) { + String sha256 = DigestUtils.sha256Hex(ins1); + try (InputStream ins2 = new FileInputStream(file)) { + HttpPost request = new WechatPayUploadHttpPost.Builder(uri) + .withImage(file.getName(), sha256, ins2) + .build(); + CloseableHttpResponse response1 = httpClient.execute(request); + } + }*/ +} diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/AccountInfo.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/AccountInfo.java new file mode 100644 index 0000000..7e46bb9 --- /dev/null +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/AccountInfo.java @@ -0,0 +1,35 @@ +package com.ruoyi.shop.util.dto; + +/** + * @ClassName AccountInfo + * @Description TODO + * @Author jqs + * @Date 2023/6/19 12:55 + * @Version 1.0 + */ + +import lombok.Data; + +import java.io.Serializable; + +/** + * 结算银行账户 + */ +@Data +public class AccountInfo implements Serializable { + private static final long serialVersionUID=1L; + /**账户类型*/ + private String bank_account_type; + /**开户银行*/ + private String account_bank; + /**开户名称*/ + private String account_name; + /**开户银行省市编码*/ + private String bank_address_code; + /**开户银行联行号*/ + private String bank_branch_id; + /**开户银行全称 (含支行)*/ + private String bank_name; + /**银行帐号*/ + private String account_number; +} diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/BusinessLicenseInfo.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/BusinessLicenseInfo.java new file mode 100644 index 0000000..e30b92d --- /dev/null +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/BusinessLicenseInfo.java @@ -0,0 +1,33 @@ +package com.ruoyi.shop.util.dto; + +/** + * @ClassName BusinessLicenseInfo + * @Description TODO + * @Author jqs + * @Date 2023/6/19 12:54 + * @Version 1.0 + */ + +import lombok.Data; + +import java.io.Serializable; + +/** + * 营业执照/登记证书信息 + */ +@Data +public class BusinessLicenseInfo implements Serializable { + private static final long serialVersionUID=1L; + /**证件扫描件*/ + private String business_license_copy; + /**证件注册号*/ + private String business_license_number; + /**商户名称*/ + private String merchant_name; + /**经营者/法定代表人姓名*/ + private String legal_person; + /**注册地址*/ + private String company_address; + /**营业期限*/ + private String business_time; +} diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/CertificateItem.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/CertificateItem.java new file mode 100644 index 0000000..5a9c13e --- /dev/null +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/CertificateItem.java @@ -0,0 +1,22 @@ +package com.ruoyi.shop.util.dto; + + +import lombok.Data; + +//平台证书item +@Data +public class CertificateItem { + + //加密的平台证书序列号 + private String serial_no; + + //加密的平台证书序列号 + private String effective_time; + + //证书弃用时间 + private String expire_time; + + //证书加密信息 + private EncryptedCertificateItem encrypt_certificate; + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/ContactInfo.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/ContactInfo.java new file mode 100644 index 0000000..d4817dd --- /dev/null +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/ContactInfo.java @@ -0,0 +1,31 @@ +package com.ruoyi.shop.util.dto; + +/** + * @ClassName ContactInfo + * @Description TODO + * @Author jqs + * @Date 2023/6/19 12:55 + * @Version 1.0 + */ + +import lombok.Data; + +import java.io.Serializable; + +/** + * 超级管理员信息 + */ +@Data +public class ContactInfo implements Serializable { + private static final long serialVersionUID=1L; + /**超级管理员类型*/ + private String contact_type; + /**超级管理员姓名*/ + private String contact_name; + /**超级管理员身份证件号码*/ + private String contact_id_card_number; + /**超级管理员手机*/ + private String mobile_phone; + /**超级管理员邮箱*/ + private String contact_email; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/EncryptedCertificateItem.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/EncryptedCertificateItem.java new file mode 100644 index 0000000..f0402b4 --- /dev/null +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/EncryptedCertificateItem.java @@ -0,0 +1,26 @@ +package com.ruoyi.shop.util.dto; + +import lombok.Data; + +/** + * @ClassName EncryptedCertificateItem + * @Description TODO + * @Author jqs + * @Date 2023/6/19 14:12 + * @Version 1.0 + */ +@Data +public class EncryptedCertificateItem { + + //加密的平台证书序列号 + private String algorithm; + + //加密的平台证书序列号 + private String nonce; + + //证书弃用时间 + private String associated_data; + + //证书弃用时间 + private String ciphertext; +} diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/IdCardInfo.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/IdCardInfo.java new file mode 100644 index 0000000..d9c8ce4 --- /dev/null +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/IdCardInfo.java @@ -0,0 +1,31 @@ +package com.ruoyi.shop.util.dto; + +/** + * @ClassName IdCardInfo + * @Description TODO + * @Author jqs + * @Date 2023/6/19 12:54 + * @Version 1.0 + */ + +import lombok.Data; + +import java.io.Serializable; + +/** + * 经营者/法人身份证信息 + */ +@Data +public class IdCardInfo implements Serializable { + private static final long serialVersionUID=1L; + /**身份证人像面照片*/ + private String id_card_copy; + /**身份证国徽面照片*/ + private String id_card_national; + /**身份证姓名*/ + private String id_card_name; + /**身份证号码*/ + private String id_card_number; + /**身份证有效期限*/ + private String id_card_valid_time; +} diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/IdDocInfo.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/IdDocInfo.java new file mode 100644 index 0000000..0656198 --- /dev/null +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/IdDocInfo.java @@ -0,0 +1,29 @@ +package com.ruoyi.shop.util.dto; + +/** + * @ClassName IdDocInfo + * @Description TODO + * @Author jqs + * @Date 2023/6/19 12:55 + * @Version 1.0 + */ + +import lombok.Data; + +import java.io.Serializable; + +/** + * 经营者/法人其他类型证件信息 + */ +@Data +public class IdDocInfo implements Serializable { + private static final long serialVersionUID=1L; + /**证件姓名*/ + private String id_doc_name; + /**证件号码*/ + private String id_doc_number; + /**证件照片*/ + private String id_doc_copy; + /**证件结束日期*/ + private String doc_period_end; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/OrganizationCertInfo.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/OrganizationCertInfo.java new file mode 100644 index 0000000..d656e02 --- /dev/null +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/OrganizationCertInfo.java @@ -0,0 +1,27 @@ +package com.ruoyi.shop.util.dto; + +/** + * @ClassName OrganizationCertInfo + * @Description TODO + * @Author jqs + * @Date 2023/6/19 12:54 + * @Version 1.0 + */ + +import lombok.Data; + +import java.io.Serializable; + +/** + * 组织机构代码证信息 + */ +@Data +public class OrganizationCertInfo implements Serializable { + private static final long serialVersionUID=1L; + /**组织机构代码证照片*/ + private String organization_copy; + /**组织机构代码*/ + private String organization_number; + /**组织机构代码有效期限*/ + private String organization_time; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/PlainCertificateItem.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/PlainCertificateItem.java new file mode 100644 index 0000000..1db8021 --- /dev/null +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/PlainCertificateItem.java @@ -0,0 +1,23 @@ +package com.ruoyi.shop.util.dto; + +import lombok.Data; + +/** + * @ClassName PlainCertificateItem + * @Description TODO + * @Author jqs + * @Date 2023/6/19 14:14 + * @Version 1.0 + */ +@Data +public class PlainCertificateItem { + + private String serialNo; + + private String effectiveTime; + + private String expireTime; + + private String plainCertificate; + +} diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/SalesSceneInfo.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/SalesSceneInfo.java new file mode 100644 index 0000000..806bf65 --- /dev/null +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/SalesSceneInfo.java @@ -0,0 +1,29 @@ +package com.ruoyi.shop.util.dto; + +/** + * @ClassName SalesSceneInfo + * @Description TODO + * @Author jqs + * @Date 2023/6/19 12:56 + * @Version 1.0 + */ + +import lombok.Data; + +import java.io.Serializable; + +/** + * 店铺信息 + */ +@Data +public class SalesSceneInfo implements Serializable { + private static final long serialVersionUID=1L; + /**店铺名称*/ + private String store_name; + /**店铺链接*/ + private String store_url; + /**店铺二维码*/ + private String store_qr_code; + /**小程序AppID*/ + private String mini_program_sub_appid; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/SubmitInfo.java b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/SubmitInfo.java new file mode 100644 index 0000000..b6aad20 --- /dev/null +++ b/ruoyi-modules/ruoyi-shop/src/main/java/com/ruoyi/shop/util/dto/SubmitInfo.java @@ -0,0 +1,51 @@ +package com.ruoyi.shop.util.dto; + +/** + * @ClassName SubmitInfo + * @Description TODO + * @Author jqs + * @Date 2023/6/19 12:53 + * @Version 1.0 + */ + +import lombok.Data; + +import java.io.Serializable; + +/** + * 进件信息 + */ +@Data +public class SubmitInfo implements Serializable { + private static final long serialVersionUID=1L; + /**业务申请编号*/ + private String out_request_no; + /**主体类型*/ + private String organization_type; + /**营业执照/登记证书信息*/ + private BusinessLicenseInfo business_license_info; + /**组织机构代码证信息*/ + private OrganizationCertInfo organization_cert_info; + /**经营者/法人证件类型*/ + private String id_doc_type; + /**经营者/法人身份证信息*/ + private IdCardInfo id_card_info; + /**经营者/法人其他类型证件信息*/ + private IdDocInfo id_doc_info; + /**是否填写结算银行账户*/ + private Boolean need_account_info; + /**结算银行账户*/ + private AccountInfo account_info; + /**超级管理员信息*/ + private ContactInfo contact_info; + /**店铺信息*/ + private SalesSceneInfo sales_scene_info; + /**商户简称*/ + private String merchant_shortname; + /**特殊资质*/ + private String qualifications; + /**补充材料*/ + private String business_addition_pics; + /**补充说明*/ + private String business_addition_desc; +} -- Gitblit v1.7.1