From faa943df0a8402f6ea7af73f14b415b86ffe5fb2 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Fri, 21 Feb 2025 16:21:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=95=86=E5=AE=B6=E5=85=A5=E9=A9=BB=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/AccountUserBaseServiceImpl.java | 19 +- .../mall/auth/controller/AuthController.java | 5 +- .../common/modules/esign/EsignContract.java | 70 +++ .../esign/EsignContractFillingFile.java | 70 +++ .../modules/esign/EsignContractParty.java | 71 +++ .../common/modules/merch/ShopMerchEntry.java | 163 ++++++ .../mall/common/utils/StringUtils.java | 124 ++++- .../impl/AccountBaseConfigServiceImpl.java | 17 +- .../controller/admin/EsignController.java | 34 ++ .../EsignContractFillingFileMapper.java | 17 + .../EsignContractFillingFileService.java | 12 + .../esign/service/FileAndTemplateService.java | 23 + .../EsignContractFillingFileServiceImpl.java | 19 + .../impl/FileAndTemplateServiceImpl.java | 83 ++++ .../mall/shop/esign/utils/comm/AESUtils.java | 99 ++++ .../esign/utils/comm/EsignCoreSdkInfo.java | 26 + .../esign/utils/comm/EsignEncryption.java | 375 ++++++++++++++ .../shop/esign/utils/comm/EsignFileBean.java | 56 +++ .../esign/utils/comm/EsignHttpCfgHelper.java | 465 ++++++++++++++++++ .../esign/utils/comm/EsignHttpHelper.java | 167 +++++++ .../esign/utils/comm/EsignHttpResponse.java | 28 ++ .../esign/utils/comm/FileTransformation.java | 284 +++++++++++ .../utils/enums/EsignHeaderConstant.java | 28 ++ .../esign/utils/enums/EsignRequestType.java | 39 ++ .../utils/exception/EsignDemoException.java | 35 ++ .../lakala/controller/LklTkController.java | 2 +- .../admin/ShopMerchEntryAdminController.java | 56 +++ .../mobile/ShopMerchEntryController.java | 56 +++ .../merch/mapper/ShopMerchEntryMapper.java | 17 + .../merch/service/ShopMerchEntryService.java | 72 +++ .../impl/ShopMerchEntryServiceImpl.java | 313 ++++++++++++ ...StoreSameCityTransportBaseServiceImpl.java | 98 ++-- .../src/main/resources/bootstrap-local.yml | 9 +- .../esign/EsignContractFillingFileMapper.xml | 8 + .../mapper/merch/ShopMerchEntryMapper.xml | 8 + 35 files changed, 2899 insertions(+), 69 deletions(-) create mode 100644 mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContract.java create mode 100644 mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContractFillingFile.java create mode 100644 mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContractParty.java create mode 100644 mall-common/src/main/java/com/suisung/mall/common/modules/merch/ShopMerchEntry.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/esign/controller/admin/EsignController.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/esign/mapper/EsignContractFillingFileMapper.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignContractFillingFileService.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/esign/service/FileAndTemplateService.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractFillingFileServiceImpl.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/FileAndTemplateServiceImpl.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/AESUtils.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignCoreSdkInfo.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignEncryption.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignFileBean.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignHttpCfgHelper.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignHttpHelper.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignHttpResponse.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/FileTransformation.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/enums/EsignHeaderConstant.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/enums/EsignRequestType.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/exception/EsignDemoException.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/merch/controller/admin/ShopMerchEntryAdminController.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/merch/controller/mobile/ShopMerchEntryController.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/merch/mapper/ShopMerchEntryMapper.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/merch/service/ShopMerchEntryService.java create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/merch/service/impl/ShopMerchEntryServiceImpl.java create mode 100644 mall-shop/src/main/resources/mapper/esign/EsignContractFillingFileMapper.xml create mode 100644 mall-shop/src/main/resources/mapper/merch/ShopMerchEntryMapper.xml diff --git a/mall-account/src/main/java/com/suisung/mall/account/service/impl/AccountUserBaseServiceImpl.java b/mall-account/src/main/java/com/suisung/mall/account/service/impl/AccountUserBaseServiceImpl.java index f7de8b53..aacd85f9 100644 --- a/mall-account/src/main/java/com/suisung/mall/account/service/impl/AccountUserBaseServiceImpl.java +++ b/mall-account/src/main/java/com/suisung/mall/account/service/impl/AccountUserBaseServiceImpl.java @@ -59,7 +59,6 @@ import com.suisung.mall.common.utils.pojo.dto.EmailDTO; import com.suisung.mall.core.web.service.CloundService; import com.suisung.mall.core.web.service.RedisService; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; -import com.sun.javafx.geom.ConcentricShapePair; import io.seata.common.util.StringUtils; import io.seata.spring.annotation.GlobalTransactional; import org.slf4j.Logger; @@ -94,6 +93,7 @@ import static com.suisung.mall.common.utils.I18nUtil._; public class AccountUserBaseServiceImpl extends BaseServiceImpl implements AccountUserBaseService { private final String VERIFY_CODE_KEY = "register:verifyCode:"; + private final Logger logger = LoggerFactory.getLogger(AccountUserBaseServiceImpl.class); @Autowired private AuthService authService; @Autowired @@ -138,7 +138,6 @@ public class AccountUserBaseServiceImpl extends BaseServiceImpl params) { @@ -157,7 +156,9 @@ public class AccountUserBaseServiceImpl extends BaseServiceImpl adminMap = BeanUtil.beanToMap(admin); Map userInfoMap = BeanUtil.beanToMap(userInfo); - if (ObjectUtil.isNull(userInfo)) return adminMap; + if (ObjectUtil.isNull(userInfo)) { + return adminMap; + } adminMap.putAll(userInfoMap); @@ -2968,11 +2971,11 @@ public class AccountUserBaseServiceImpl extends BaseServiceImpl cls = entity.getClass(); TableInfo tableInfo = TableInfoHelper.getTableInfo(cls); - Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!", new Object[0]); + Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!"); String keyProperty = tableInfo.getKeyProperty(); - Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!", new Object[0]); + Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!"); Object idVal = ReflectionKit.getFieldValue(entity, tableInfo.getKeyProperty()); - flag = !com.baomidou.mybatisplus.core.toolkit.StringUtils.checkValNull(idVal) && !Objects.isNull(this.getById((Serializable)idVal)) ? this.edit(entity) : this.add(entity); + flag = !com.baomidou.mybatisplus.core.toolkit.StringUtils.checkValNull(idVal) && !Objects.isNull(this.getById((Serializable) idVal)) ? this.edit(entity) : this.add(entity); } return Pair.of(flag, entity); diff --git a/mall-auth/src/main/java/com/suisung/mall/auth/controller/AuthController.java b/mall-auth/src/main/java/com/suisung/mall/auth/controller/AuthController.java index 266e95c9..4bcabf99 100644 --- a/mall-auth/src/main/java/com/suisung/mall/auth/controller/AuthController.java +++ b/mall-auth/src/main/java/com/suisung/mall/auth/controller/AuthController.java @@ -13,7 +13,6 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint; -import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; @@ -31,7 +30,7 @@ import java.util.Map; @RequestMapping("/oauth") public class AuthController { - private static Logger logger = LoggerFactory.getLogger(AuthController.class); + private static final Logger logger = LoggerFactory.getLogger(AuthController.class); @Autowired private TokenEndpoint tokenEndpoint; @@ -46,7 +45,7 @@ public class AuthController { @ApiImplicitParam(name = "password", value = "登录密码") }) @RequestMapping(value = "/token", method = RequestMethod.POST) - public CommonResult postAccessToken(@ApiIgnore Principal principal, @ApiIgnore @RequestParam Map parameters) throws HttpRequestMethodNotSupportedException { + public CommonResult postAccessToken(@ApiIgnore Principal principal, @ApiIgnore @RequestParam Map parameters) { OAuth2AccessToken oAuth2AccessToken = null; Oauth2TokenDto oauth2TokenDto = null; try { diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContract.java b/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContract.java new file mode 100644 index 00000000..b4f7e357 --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContract.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.common.modules.esign; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("esign_contract") +@ApiModel(value = "EsignContract 对象", description = "合作多方电子签名审核主表") +public class EsignContract implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.INPUT) + @ApiModelProperty(value = "自增ID") + private Long id; + + @ApiModelProperty(value = "店铺编号") + private String store_id; + + @ApiModelProperty(value = "合同编号,自定义生成") + private String contract_number; + + @ApiModelProperty(value = "合同名称") + private String contract_name; + + @ApiModelProperty(value = "合同模版Id") + private String doc_template_id; + + @ApiModelProperty(value = "生成的未签署合同地址(30天有效期)") + private String unsigned_contract_url; + + @ApiModelProperty(value = "生成的未签署合同地址(30天有效期)") + private String signed_contract_url; + + @ApiModelProperty(value = "未签署合同地址本地下载地址") + private String local_contract_url; + + @ApiModelProperty(value = "记录状态:1-有效;2-无效;") + private Integer status; + + @ApiModelProperty(value = "创建人用户ID") + private String created_by; + + @ApiModelProperty(value = "修改人用户ID") + private String updated_by; + + @ApiModelProperty(value = "记录创建时间") + private Date created_at; + + @ApiModelProperty(value = "记录更新时间") + private Date updated_at; +} diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContractFillingFile.java b/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContractFillingFile.java new file mode 100644 index 00000000..c2e99db1 --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContractFillingFile.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.common.modules.esign; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("esign_contract_filling_file") +@ApiModel(value = "EsignContractFillingFile 对象", description = "待签署合同填充的文件表") +public class EsignContractFillingFile implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.INPUT) + @ApiModelProperty(value = "自增ID") + private Long id; + + @ApiModelProperty(value = "店铺编号") + private String store_id; + + @ApiModelProperty(value = "合同编号,自定义生成") + private String contract_number; + + @ApiModelProperty(value = "合同名称") + private String contract_name; + + @ApiModelProperty(value = "模版编号") + private String doc_template_id; + + @ApiModelProperty(value = "模版填充json键值对数据") + private String doc_template_filling_values; + + @ApiModelProperty(value = "生成的未签署合同地址(30天有效期)") + private String unsigned_contract_url; + + @ApiModelProperty(value = "未签署合同地址本地下载地址") + private String unsigned_contract_local_url; + + @ApiModelProperty(value = "记录状态:1-有效;2-无效;") + private Integer status; + + @ApiModelProperty(value = "创建人用户ID") + private String created_by; + + @ApiModelProperty(value = "修改人用户ID") + private String updated_by; + + @ApiModelProperty(value = "记录创建时间") + private Date created_at; + + @ApiModelProperty(value = "记录更新时间") + private Date updated_at; +} diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContractParty.java b/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContractParty.java new file mode 100644 index 00000000..cbb2f99c --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContractParty.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.common.modules.esign; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("esign_contract_party") +@ApiModel(value = "EsignContractParty 对象", description = "合作多方电子签名审核子项表(多合作方)") +public class EsignContractParty implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.INPUT) + @ApiModelProperty(value = "自增ID") + private Long id; + + @ApiModelProperty(value = "合同编号,自定义生成") + private String contract_number; + + @ApiModelProperty(value = "合作方名称") + private String party_name; + + @ApiModelProperty(value = "合作方签署状态:1-签署;2-未签署;") + private Integer sign_status; + + @ApiModelProperty(value = "合作方签署时间") + private Date sign_time; + + @ApiModelProperty(value = "合作方签署方式:1-人脸识别;2-身份证认证;") + private Integer sign_style; + + @ApiModelProperty(value = "是否签署方:1-发起方;2-签署方;") + private Integer is_signer; + + @ApiModelProperty(value = "合作方审核状态:1-审核已通过;2-审核未通过;") + private String audit_status; + + @ApiModelProperty(value = "合作方审核意见") + private String audit_remark; + + @ApiModelProperty(value = "签署流程ID") + private String sign_flow_id; + + @ApiModelProperty(value = "签署流程主题") + private String sign_flow_title; + + + @ApiModelProperty(value = "记录创建时间") + private Date created_at; + + @ApiModelProperty(value = "记录更新时间") + private Date updated_at; +} diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/merch/ShopMerchEntry.java b/mall-common/src/main/java/com/suisung/mall/common/modules/merch/ShopMerchEntry.java new file mode 100644 index 00000000..8a0e5726 --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/merch/ShopMerchEntry.java @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.common.modules.merch; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("shop_mch_entry") +@ApiModel(value = "ShopMerchEntry 实体", description = "商家入驻信息表") +public class ShopMerchEntry implements Serializable { + private static final long serialVersionUID = 1L; + + @ApiModelProperty(value = "自增ID") + @TableId(value = "id", type = IdType.INPUT) + private Long id; + + @ApiModelProperty(value = "入驻商家的登录手机号") + private String login_mobile; + + @ApiModelProperty(value = "商家店铺的ID") + private String store_id; + + @ApiModelProperty(value = "商家店铺的名称") + private String store_name; + + @ApiModelProperty(value = "入驻商家的联系人姓名") + private String contact_name; + + @ApiModelProperty(value = "商家经营的类目,用数字表示不同类目") + private Integer biz_category; + + @ApiModelProperty(value = "除去运费的商家分成比列,如:95.00,最大100,最小0") + private String split_ratio; + + @ApiModelProperty(value = "分账到账方式:1-T+0;2-T+1,3-T+3...") + private Integer settlement_method; + + @ApiModelProperty(value = "商家入驻合同的编号") + private String contract_number; + + @ApiModelProperty(value = "入驻商家正式合同的下载地址") + private String contract_download_url; + + @ApiModelProperty(value = "入驻商家店铺经度") + private String store_longitude; + + @ApiModelProperty(value = "入驻商家店铺维度") + private String store_latitude; + + @ApiModelProperty(value = "入驻商家店铺所在的省") + private String province_id; + + @ApiModelProperty(value = "入驻商家店铺所在的市") + private String city_id; + + @ApiModelProperty(value = "入驻商家店铺所在的县区") + private String county_id; + + @ApiModelProperty(value = "入驻商家店铺的详细地址") + private String store_address; + + @ApiModelProperty(value = "入驻商家店铺门面正面图片的存储路径") + private String front_facade_image; + + @ApiModelProperty(value = "入驻商家店铺门面环境图片的存储路径") + private String environment_image; + + @ApiModelProperty(value = "入驻主体类型,企业或个人:1-企业;2-个人;") + private Integer entity_type; + + @ApiModelProperty(value = "企业入驻时的营业执照编号") + private String biz_license_number; + + @ApiModelProperty(value = "入驻商家营业执照图片的存储路径") + private String biz_license_image; + + @ApiModelProperty(value = "入驻商家的许可证类型:1-许可证;2-特许证件,3-其他证件") + private Integer license_type; + + @ApiModelProperty(value = "入驻商家的许可证编号") + private String license_number; + + @ApiModelProperty(value = "入驻商家许可证图片的存储路径") + private String license_image; + + @ApiModelProperty(value = "入驻商家的法人姓名") + private String legal_person_name; + + @ApiModelProperty(value = "入驻商家的法人姓名") + private String legal_person_mobile; + + @ApiModelProperty(value = "入驻商家的法人身份证号码") + private String legal_person_id_number; + + @ApiModelProperty(value = "入驻商家法人身份证正面图片的存储路径") + private String legal_person_id_images; + + @ApiModelProperty(value = "入驻商家法人身份证反面图片的存储路径") + private String legal_person_id_images2; + + @ApiModelProperty(value = "个人入驻时的身份证号码") + private String individual_id_number; + + @ApiModelProperty(value = "个人入驻时身份证正面图片的存储路径") + private String individual_id_images; + + @ApiModelProperty(value = "个人入驻时身份证反面图片的存储路径") + private String individual_id_images2; + + @ApiModelProperty(value = "入驻商家的开户银行") + private String bank_name; + + @ApiModelProperty(value = "入驻商家开户银行的支行名称") + private String bank_branch_name; + + @ApiModelProperty(value = "入驻商家的收款账户号码") + private String account_number; + + + @ApiModelProperty(value = "入驻商家的收款账户姓名") + private String account_holder_name; + + + @ApiModelProperty(value = "入驻商家的审批状态:1-已通过;2-未通过;3-待审核;") + private Integer approval_status; + + @ApiModelProperty(value = "入驻商家审批时的备注信息") + private String approval_remark; + + + @ApiModelProperty(value = "该商家入驻记录是否有效,0:无效,1:有效") + private Integer status; + + @ApiModelProperty(value = "创建该商家入驻记录的用户") + private String created_by; + + @ApiModelProperty(value = "最后修改该商家入驻记录的用户") + private String updated_by; + + @ApiModelProperty(value = "商家入驻记录的创建时间") + private Date created_at; + + @ApiModelProperty(value = "商家入驻记录的更新时间") + private Date updated_at; +} diff --git a/mall-common/src/main/java/com/suisung/mall/common/utils/StringUtils.java b/mall-common/src/main/java/com/suisung/mall/common/utils/StringUtils.java index e8e435f2..6d538d06 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/utils/StringUtils.java +++ b/mall-common/src/main/java/com/suisung/mall/common/utils/StringUtils.java @@ -1,15 +1,12 @@ package com.suisung.mall.common.utils; import cn.hutool.core.util.StrUtil; -import cn.hutool.json.JSONUtil; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.xml.sax.InputSource; -import com.fasterxml.jackson.databind.PropertyNamingStrategy; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -359,18 +356,20 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils { /** * 将 JSON 字符串中驼峰命名的键转换为下划线命名 + * * @param jsonString 输入的 JSON 字符串 * @return 转换后的 JSON 字符串 */ public static String convertCamelToSnake(String jsonString) { Gson gson = new Gson(); JsonElement jsonElement = JsonParser.parseString(jsonString); - JsonElement convertedElement = convertKeys(jsonElement,true); + JsonElement convertedElement = convertKeys(jsonElement, true); return gson.toJson(convertedElement); } /** * 将 JSON 字符串中蛇形命名的键转换为驼峰命名 + * * @param jsonString 输入的 JSON 字符串 * @return 转换后的 JSON 字符串 */ @@ -379,13 +378,14 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils { // 解析 JSON 字符串为 JsonElement 对象 JsonElement jsonElement = JsonParser.parseString(jsonString); // 递归转换键名 - JsonElement convertedElement = convertKeys(jsonElement,true); + JsonElement convertedElement = convertKeys(jsonElement, true); // 将转换后的 JsonElement 转换回 JSON 字符串 return gson.toJson(convertedElement); } /** * 递归转换 JSON 元素中的键名 + * * @param element 要转换的 JSON 元素 * @return 转换后的 JSON 元素 */ @@ -395,10 +395,10 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils { JsonObject newJsonObject = new JsonObject(); for (Map.Entry entry : jsonObject.entrySet()) { - String newKey ; - if(isCamelToSnake) { + String newKey; + if (isCamelToSnake) { newKey = camelToSnake(entry.getKey()); - }else{ + } else { newKey = snakeToCamel(entry.getKey()); } JsonElement value = entry.getValue(); @@ -417,9 +417,9 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils { } - /** * 将单个驼峰命名的字符串转换为下划线命名 + * * @param camelCase 驼峰命名的字符串 * @return 下划线命名的字符串 */ @@ -437,6 +437,7 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils { /** * 将单个蛇形命名的字符串转换为驼峰命名 + * * @param snakeCase 蛇形命名的字符串 * @return 驼峰命名的字符串 */ @@ -462,6 +463,7 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils { /** * 根据文件名获取文件后缀 + * * @param fileName 文件名 * @return 文件后缀,如果没有后缀则返回空字符串 */ @@ -476,6 +478,110 @@ public final class StringUtils extends org.apache.commons.lang3.StringUtils { return fileName.substring(lastIndex + 1); } + /** + * 校验内地身份证号码 + * + * @param idCard 身份证号码 + * @return 是否有效 + */ + public static boolean validateMainlandIDCard(String idCard) { + if (idCard == null || idCard.length() != 18) { + return false; + } + return Pattern.matches("^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9Xx]$", idCard); + } + + /** + * 校验香港身份证号码 + * + * @param idCard 身份证号码 + * @return 是否有效 + */ + public static boolean validateHongKongIDCard(String idCard) { + if (idCard == null) { + return false; + } + idCard = idCard.toUpperCase(); + if (!Pattern.matches("^[A-Z]{1,2}\\d{6}[\\dA]$", idCard)) { + return false; + } + // 计算校验码 + int sum = 0; + if (idCard.length() == 9) { + sum += (idCard.charAt(0) - 55) * 8; + sum += (idCard.charAt(1) - 55) * 7; + } else { + sum += 36 * 8; + sum += (idCard.charAt(0) - 55) * 7; + } + sum += (idCard.charAt(idCard.length() - 7) - 48) * 6; + sum += (idCard.charAt(idCard.length() - 6) - 48) * 5; + sum += (idCard.charAt(idCard.length() - 5) - 48) * 4; + sum += (idCard.charAt(idCard.length() - 4) - 48) * 3; + sum += (idCard.charAt(idCard.length() - 3) - 48) * 2; + sum += (idCard.charAt(idCard.length() - 2) - 48); + int remainder = sum % 11; + int checkDigit = 11 - remainder; + if (checkDigit == 11) { + checkDigit = 0; + } else if (checkDigit == 10) { + checkDigit = 'A'; + } + char lastChar = idCard.charAt(idCard.length() - 1); + return (checkDigit == (lastChar >= '0' && lastChar <= '9' ? lastChar - 48 : lastChar)); + } + + /** + * 校验澳门身份证号码 + * + * @param idCard 身份证号码 + * @return 是否有效 + */ + public static boolean validateMacaoIDCard(String idCard) { + if (idCard == null) { + return false; + } + return Pattern.matches("^[1|5|7]\\d{6}[\\dA]$", idCard); + } + + /** + * 校验台湾身份证号码 + * + * @param idCard 身份证号码 + * @return 是否有效 + */ + public static boolean validateTaiwanIDCard(String idCard) { + if (idCard == null || idCard.length() != 10) { + return false; + } + if (!Pattern.matches("^[A-Z][12]\\d{8}$", idCard)) { + return false; + } + // 计算校验码 + int[] weights = {1, 9, 8, 7, 6, 5, 4, 3, 2, 1}; + int[] areaCodes = {10, 11, 12, 13, 14, 15, 16, 17, 34, 18, 19, 20, 21, 22, 35, 23, 24, 25, 26, 27, 28, 29, 32, 30, 31, 33}; + int sum = 0; + char firstChar = idCard.charAt(0); + int areaIndex = firstChar - 'A'; + int areaValue = areaCodes[areaIndex]; + sum += areaValue / 10 * weights[0]; + sum += areaValue % 10 * weights[1]; + for (int i = 1; i < 9; i++) { + sum += (idCard.charAt(i) - '0') * weights[i + 1]; + } + int checkDigit = (10 - sum % 10) % 10; + return checkDigit == (idCard.charAt(9) - '0'); + } + + /** + * 综合校验身份证号码 + * + * @param idCard 身份证号码 + * @return 是否有效 + */ + public static boolean validateIDCard(String idCard) { + return validateMainlandIDCard(idCard) || validateHongKongIDCard(idCard) || validateMacaoIDCard(idCard) || validateTaiwanIDCard(idCard); + } /** diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/AccountBaseConfigServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/AccountBaseConfigServiceImpl.java index 77784cfd..cc8ac0f1 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/AccountBaseConfigServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/AccountBaseConfigServiceImpl.java @@ -46,16 +46,13 @@ import java.util.stream.Collectors; @Slf4j public class AccountBaseConfigServiceImpl extends BaseServiceImpl implements AccountBaseConfigService, CommandLineRunner { + public static Map configMap; + public static Long version = 0L; @Autowired private AccountService accountService; - @Autowired private RedisService redisService; - public static Map configMap; - - public static Long version = 0L; - /** * 根据config_key 获取 config_value * @@ -63,9 +60,15 @@ public class AccountBaseConfigServiceImpl extends BaseServiceImpl { +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignContractFillingFileService.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignContractFillingFileService.java new file mode 100644 index 00000000..ed1225fa --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignContractFillingFileService.java @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.esign.service; + +public interface EsignContractFillingFileService { +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/FileAndTemplateService.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/FileAndTemplateService.java new file mode 100644 index 00000000..542083d4 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/FileAndTemplateService.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.esign.service; + +import com.suisung.mall.common.modules.esign.EsignContractFillingFile; + +public interface FileAndTemplateService { + + /** + * 填充合同模版,生成合同文件地址 + * + * @param storeId + * @param docTemplateId + * @return + */ + EsignContractFillingFile fillDocTemplate(String storeId, String docTemplateId); +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractFillingFileServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractFillingFileServiceImpl.java new file mode 100644 index 00000000..5b5dcb73 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractFillingFileServiceImpl.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.esign.service.impl; + +import com.suisung.mall.common.modules.esign.EsignContractFillingFile; +import com.suisung.mall.core.web.service.impl.BaseServiceImpl; +import com.suisung.mall.shop.esign.mapper.EsignContractFillingFileMapper; +import com.suisung.mall.shop.esign.service.EsignContractFillingFileService; +import org.springframework.stereotype.Service; + +@Service +public class EsignContractFillingFileServiceImpl extends BaseServiceImpl implements EsignContractFillingFileService { +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/FileAndTemplateServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/FileAndTemplateServiceImpl.java new file mode 100644 index 00000000..5a50ea9b --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/FileAndTemplateServiceImpl.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.esign.service.impl; + +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.suisung.mall.common.modules.esign.EsignContractFillingFile; +import com.suisung.mall.shop.esign.service.FileAndTemplateService; +import com.suisung.mall.shop.esign.utils.comm.EsignHttpHelper; +import com.suisung.mall.shop.esign.utils.comm.EsignHttpResponse; +import com.suisung.mall.shop.esign.utils.enums.EsignRequestType; +import com.suisung.mall.shop.esign.utils.exception.EsignDemoException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.Map; + +@Slf4j +@Service +public class FileAndTemplateServiceImpl implements FileAndTemplateService { + @Value("${esign.server_url}") + private String serverUrl; + + @Value("${esign.app_id}") + private String appId; + + @Value("${esign.app_secret}") + private String appSecret; + + + /** + * 填充合同模版,生成合同文件地址 + * + * @param storeId + * @param docTemplateId + * @return + */ + @Override + public EsignContractFillingFile fillDocTemplate(String storeId, String docTemplateId) { + // 获取模版文件 + String templateId = "b411907d8f4640a1af593bea98c6b6c1"; + String apiaddr = "/v3/files/create-by-doc-template"; + + // 获取填充模版的数据 + JSONObject fillJson = new JSONObject(); + fillJson.put("docTemplateId", templateId) + .put("fileName", "小发同城入驻协议测试"); + + String componentJson = "[{'componentKey':'yf_company','componentValue':'桂平厚德贸易有限公司'},{'componentKey':'sign_date','componentValue':'2025-02-20'}]"; + fillJson.put("components", JSONUtil.parseArray(componentJson)); + + String jsonParma = fillJson.toString(); + + // 填充模版操作 + /* 填写模板生成文件*/ + + //请求方法 + EsignRequestType requestType = EsignRequestType.POST; + //生成签名鉴权方式的的header + Map header = null; + try { + header = EsignHttpHelper.signAndBuildSignAndJsonHeader(appId, appSecret, jsonParma, requestType.name(), apiaddr, true); + //发起接口请求 + EsignHttpResponse createByDocTemplate = EsignHttpHelper.doCommHttp(serverUrl, apiaddr, requestType, jsonParma, header, true); + + log.info("{}", createByDocTemplate); + } catch (EsignDemoException e) { + throw new RuntimeException(e); + } + + + EsignContractFillingFile esignContractFillingFile = new EsignContractFillingFile(); +// esignContractFillingFile.set + return esignContractFillingFile; + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/AESUtils.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/AESUtils.java new file mode 100644 index 00000000..1c36c9ac --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/AESUtils.java @@ -0,0 +1,99 @@ +/* + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.suisung.mall.shop.esign.utils.comm; + +import org.apache.commons.codec.binary.Base64; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +/** + * AES对称加密工具类 + * + * @author 澄泓 + * @date 2019年7月18日 + */ +public class AESUtils { + + private static final String KEY_ALGORITHM = "AES"; + // AES/GCM加密算法,不用补位 + private static final String DEFAULT_CIPHER_ALGORITHM = "AES/GCM/NoPadding"; + + /** + * AES 加密操作 + * + * @param content 待加密内容 + * @param AESSecret AES秘钥 + * @return 返回Base64转码后的加密数据 + */ + public static String encrypt(String content, String AESSecret) { + try { + Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM); + cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(AESSecret), KEY_ALGORITHM)); + byte[] iv = cipher.getIV(); + assert iv.length == 12; + byte[] encryptData = cipher.doFinal(content.getBytes()); + assert encryptData.length == content.getBytes().length + 16; + byte[] message = new byte[12 + content.getBytes().length + 16]; + System.arraycopy(iv, 0, message, 0, 12); + System.arraycopy(encryptData, 0, message, 12, encryptData.length); + return Base64.encodeBase64URLSafeString(message); + } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException + | BadPaddingException e) { + e.printStackTrace(); + } + return null; + } + + /** + * AES 解密操作 + * + * @param base64Content + * @param AESSecret AES秘钥 + * @return + */ + public static String decrypt(String base64Content, String AESSecret) { + byte[] content = Base64.decodeBase64(base64Content); + if (content.length < 12 + 16) + throw new IllegalArgumentException(); + GCMParameterSpec params = new GCMParameterSpec(128, content, 0, 12); + try { + Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM); + cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(AESSecret), KEY_ALGORITHM), params); + byte[] decryptData = cipher.doFinal(content, 12, content.length - 12); + return new String(decryptData); + } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException + | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) { + e.printStackTrace(); + } + return null; + } + + public static void main(String[] args) { + // 待加密的字符串 + String s = "{\"name\":\"张三\",\"idNo\":\"320333xxxxxxx12522\"}"; + // 秘钥 + String pass = "D/RA+2esbSbfSVOQsTGlpg=="; + // 加密 + String encoded = encrypt(s, pass); + System.out.println("加密之前:" + s); + System.out.println("加密结果:" + encoded); + System.out.println("解密结果:" + decrypt(encoded, pass)); + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignCoreSdkInfo.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignCoreSdkInfo.java new file mode 100644 index 00000000..17cd0c7c --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignCoreSdkInfo.java @@ -0,0 +1,26 @@ +package com.suisung.mall.shop.esign.utils.comm; + +/** + * esignSDK-core信息类 + * + * @author 澄泓 + * @date 2022/2/22 13:59 + */ +public class EsignCoreSdkInfo { + private static final String SdkVersion = "Esign-Sdk-Core1.0"; + private static final String SupportedVersion = "JDK1.7 MORE THAN"; + + private static final String Info = "sdk-esign-api核心工具包,主要处理e签宝公有云产品接口调用时的签名计算以及网络请求,通过EsignHttpHelper.signAndBuildSignAndJsonHeader构造签名鉴权+json数据格式的请求头,通过HttpHelper.doCommHttp方法入参发起网络请求。让开发者无需关注具体的请求签名算法,专注于接口业务的json参数构造"; + + public static String getSdkVersion() { + return SdkVersion; + } + + public static String getInfo() { + return Info; + } + + public static String getSupportedVersion() { + return SupportedVersion; + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignEncryption.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignEncryption.java new file mode 100644 index 00000000..60d80076 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignEncryption.java @@ -0,0 +1,375 @@ +/* + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.suisung.mall.shop.esign.utils.comm; + +import com.suisung.mall.shop.esign.utils.exception.EsignDemoException; +import org.apache.commons.codec.binary.Base64; +import org.apache.http.message.BasicNameValuePair; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.Collator; +import java.text.MessageFormat; +import java.util.*; + +/** + * @author 澄泓 + * @description 请求数据通用处理类 + * @date 2020年10月22日 下午14:25:31 + * @since JDK1.7 + */ +public class EsignEncryption { + + /** + * 不允许外部创建实例 + */ + private EsignEncryption() { + } + + /** + * 拼接待签名字符串 + * + * @param httpMethod + * @param url + * @return + */ + public static String appendSignDataString(String httpMethod, String contentMd5, String accept, String contentType, String headers, String date, String url) throws EsignDemoException { + StringBuffer sb = new StringBuffer(); + sb.append(httpMethod).append("\n").append(accept).append("\n").append(contentMd5).append("\n") + .append(contentType).append("\n"); + + if ("".equals(date) || date == null) { + sb.append("\n"); + } else { + sb.append(date).append("\n"); + } + if ("".equals(headers) || headers == null) { + sb.append(url); + } else { + sb.append(headers).append("\n").append(url); + } + return new String(sb); + } + + /*** + * Content-MD5的计算方法 + * @param str 待计算的消息 + * @return MD5计算后摘要值的Base64编码(ContentMD5) + * @throws EsignDemoException 加密过程中的异常信息 + */ + public static String doContentMD5(String str) throws EsignDemoException { + byte[] md5Bytes = null; + MessageDigest md5 = null; + String contentMD5 = null; + try { + md5 = MessageDigest.getInstance("MD5"); + // 计算md5函数 + md5.update(str.getBytes(StandardCharsets.UTF_8)); + // 获取文件MD5的二进制数组(128位) + md5Bytes = md5.digest(); + // 把MD5摘要后的二进制数组md5Bytes使用Base64进行编码(而不是对32位的16进制字符串进行编码) + contentMD5 = Base64.encodeBase64String(md5Bytes); + + } catch (NoSuchAlgorithmException e) { + EsignDemoException ex = new EsignDemoException("不支持此算法", e); + ex.initCause(e); + throw ex; + } + return contentMD5; + } + + /*** + * 计算请求签名值-HmacSHA256摘要 + * @param message 待签名字符串 + * @param secret 密钥APP KEY + * @return reqSignature HmacSHA256计算后摘要值的Base64编码 + * @throws EsignDemoException 加密过程中的异常信息 + */ + public static String doSignatureBase64(String message, String secret) throws EsignDemoException { + String algorithm = "HmacSHA256"; + Mac hmacSha256; + String digestBase64 = null; + try { + hmacSha256 = Mac.getInstance(algorithm); + byte[] keyBytes = secret.getBytes(StandardCharsets.UTF_8); + byte[] messageBytes = message.getBytes(StandardCharsets.UTF_8); + hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, algorithm)); + // 使用HmacSHA256对二进制数据消息Bytes计算摘要 + byte[] digestBytes = hmacSha256.doFinal(messageBytes); + // 把摘要后的结果digestBytes使用Base64进行编码 + digestBase64 = Base64.encodeBase64String(digestBytes); + } catch (NoSuchAlgorithmException e) { + EsignDemoException ex = new EsignDemoException("不支持此算法", e); + ex.initCause(e); + throw ex; + } catch (InvalidKeyException e) { + EsignDemoException ex = new EsignDemoException("无效的密钥规范", e); + ex.initCause(e); + throw ex; + } + return digestBase64; + } + + /** + * 获取时间戳 + * + * @return + */ + public static String timeStamp() { + long timeStamp = System.currentTimeMillis(); + return String.valueOf(timeStamp); + } + + /** + * byte字节数组转换成字符串 + * + * @param b + * @return + */ + public static String byteArrayToHexString(byte[] b) { + StringBuilder hs = new StringBuilder(); + String stmp; + for (int n = 0; b != null && n < b.length; n++) { + stmp = Integer.toHexString(b[n] & 0XFF); + if (stmp.length() == 1) + hs.append('0'); + hs.append(stmp); + } + return hs.toString().toLowerCase(); + } + + /** + * hash散列加密算法 + * + * @return + */ + public static String Hmac_SHA256(String message, String key) throws EsignDemoException { + byte[] rawHmac = null; + try { + SecretKeySpec sk = new SecretKeySpec(key.getBytes(), "HmacSHA256"); + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(sk); + rawHmac = mac.doFinal(message.getBytes()); + } catch (InvalidKeyException e) { + EsignDemoException ex = new EsignDemoException("无效的密钥规范", e); + ex.initCause(e); + throw ex; + } catch (NoSuchAlgorithmException e) { + EsignDemoException ex = new EsignDemoException("不支持此算法", e); + ex.initCause(e); + throw ex; + } catch (Exception e) { + EsignDemoException ex = new EsignDemoException("hash散列加密算法报错", e); + ex.initCause(e); + throw ex; + } finally { + return byteArrayToHexString(rawHmac); + } + + } + + /** + * MD5加密32位 + */ + public static String MD5Digest(String text) throws EsignDemoException { + byte[] digest = null; + try { + MessageDigest md5 = MessageDigest.getInstance("MD5"); + md5.update(text.getBytes()); + digest = md5.digest(); + } catch (NoSuchAlgorithmException e) { + EsignDemoException ex = new EsignDemoException("不支持此算法", e); + ex.initCause(e); + throw ex; + } finally { + return byteArrayToHexString(digest); + } + + } + + public static void formDataSort(List param) { + Collections.sort(param, new Comparator() { + @Override + public int compare(BasicNameValuePair o1, BasicNameValuePair o2) { + Comparator com = Collator.getInstance(Locale.CHINA); + return com.compare(o1.getName(), o2.getName()); + } + }); + } + + /*** + * 字符串是否为空(含空格校验) + * @param str + * @return + */ + public static boolean isBlank(String str) { + if (null == str || 0 == str.length()) { + return true; + } + + int strLen = str.length(); + + for (int i = 0; i < strLen; i++) { + if (!Character.isWhitespace(str.charAt(i))) { + return false; + } + } + return true; + } + + + /*** + * 对请求URL中的Query参数按照字段名的 ASCII 码从小到大排序(字典排序) + * + * @param apiUrl + * @return 排序后的API接口地址 + * @throws Exception + */ + public static String sortApiUrl(String apiUrl) throws EsignDemoException { + + if (!apiUrl.contains("?")) { + return apiUrl; + } + + int queryIndex = apiUrl.indexOf("?"); + String apiUrlPath = apiUrl.substring(0, queryIndex + 1); + String apiUrlQuery = apiUrl.substring(queryIndex + 1); + //apiUrlQuery为空时返回 + if (isBlank(apiUrlQuery)) { + return apiUrl.substring(0, apiUrl.length() - 1); + } + // 请求URL中Query参数转成Map + Map queryParamsMap = new HashMap(); + String[] params = apiUrlQuery.split("&"); + for (String str : params) { + int index = str.indexOf("="); + String key = str.substring(0, index); + String value = str.substring(index + 1); + if (queryParamsMap.containsKey(key)) { + String msg = MessageFormat.format("请求URL中的Query参数的{0}重复", key); + throw new EsignDemoException(msg); + } + queryParamsMap.put(key, value); + } + + ArrayList queryMapKeys = new ArrayList(); + for (Map.Entry entry : queryParamsMap.entrySet()) { + queryMapKeys.add((String) entry.getKey()); + } + // 按照字段名的 ASCII 码从小到大排序(字典排序) + Collections.sort(queryMapKeys, new Comparator() { + @Override + public int compare(String o1, String o2) { + return (o1.compareToIgnoreCase(o2) == 0 ? -o1.compareTo(o2) : o1.compareToIgnoreCase(o2)); + } + }); + + StringBuffer queryString = new StringBuffer(); + // 构造Query参数键值对值对的格式 + for (int i = 0; i < queryMapKeys.size(); i++) { + String key = queryMapKeys.get(i); + String value = (String) queryParamsMap.get(key); + queryString.append(key); + queryString.append("="); + queryString.append(value); + queryString.append("&"); + } + if (queryString.length() > 0) { + queryString = queryString.deleteCharAt(queryString.length() - 1); + } + + // Query参数排序后的接口请求地址 + String sortApiUrl = apiUrlPath + + queryString; + return sortApiUrl; + } + + /** + * 获取query + * + * @param apiUrl + * @return + * @throws EsignDemoException + */ + public static ArrayList getQuery(String apiUrl) throws EsignDemoException { + ArrayList BasicNameValuePairList = new ArrayList<>(); + + if (!apiUrl.contains("?")) { + return BasicNameValuePairList; + } + + int queryIndex = apiUrl.indexOf("\\?"); + String apiUrlQuery = apiUrl.substring(queryIndex); + + // 请求URL中Query参数转成Map + Map queryParamsMap = new HashMap(); + String[] params = apiUrlQuery.split("&"); + for (String str : params) { + int index = str.indexOf("="); + String key = str.substring(0, index); + String value = str.substring(index + 1); + if (queryParamsMap.containsKey(key)) { + String msg = MessageFormat.format("请求URL中的Query参数的{0}重复", key); + throw new EsignDemoException(msg); + } + BasicNameValuePairList.add(new BasicNameValuePair(key, value)); + queryParamsMap.put(key, value); + } + return BasicNameValuePairList; + } + + /** + * + */ + public static boolean callBackCheck(String timestamp, String requestQuery, String body, String key, String signature) { + String algorithm = "HmacSHA256"; + String encoding = "UTF-8"; + Mac mac = null; + try { + String data = timestamp + requestQuery + body; + mac = Mac.getInstance(algorithm); + SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(encoding), algorithm); + mac.init(secretKey); + mac.update(data.getBytes(encoding)); + } catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException e) { + e.printStackTrace(); + System.out.println("获取Signature签名信息异常:" + e.getMessage()); + return false; + } + return byte2hex(mac.doFinal()).equalsIgnoreCase(signature); + } + + /*** + * 将byte[]转成16进制字符串 + * + * @param data + * + * @return 16进制字符串 + */ + public static String byte2hex(byte[] data) { + StringBuilder hash = new StringBuilder(); + String stmp; + for (int n = 0; data != null && n < data.length; n++) { + stmp = Integer.toHexString(data[n] & 0XFF); + if (stmp.length() == 1) + hash.append('0'); + hash.append(stmp); + } + return hash.toString(); + } + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignFileBean.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignFileBean.java new file mode 100644 index 00000000..a52323cc --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignFileBean.java @@ -0,0 +1,56 @@ +package com.suisung.mall.shop.esign.utils.comm; + +import com.suisung.mall.shop.esign.utils.exception.EsignDemoException; + +import java.io.File; + +/** + * @author 澄泓 + * @version JDK1.7 + * @description 文件基础信息封装类 + * @date 2020/10/26 14:54 + */ +public class EsignFileBean { + //文件名称 + private final String fileName; + //文件大小 + private final int fileSize; + //文件内容MD5 + private final String fileContentMD5; + //文件地址 + private final String filePath; + + + public EsignFileBean(String filePath) throws EsignDemoException { + this.filePath = filePath; + this.fileContentMD5 = FileTransformation.getFileContentMD5(filePath); + File file = new File(filePath); + if (!file.exists()) { + throw new EsignDemoException("文件不存在"); + } + this.fileName = file.getName(); + this.fileSize = (int) file.length(); + } + + public String getFileName() { + return fileName; + } + + public int getFileSize() { + return fileSize; + } + + public String getFileContentMD5() { + return fileContentMD5; + } + + /** + * 传入本地文件地址获取二进制数据 + * + * @return + * @throws EsignDemoException + */ + public byte[] getFileBytes() throws EsignDemoException { + return FileTransformation.fileToBytes(filePath); + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignHttpCfgHelper.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignHttpCfgHelper.java new file mode 100644 index 00000000..ad58fe4c --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignHttpCfgHelper.java @@ -0,0 +1,465 @@ +/* + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.suisung.mall.shop.esign.utils.comm; + +import com.suisung.mall.shop.esign.utils.enums.EsignRequestType; +import com.suisung.mall.shop.esign.utils.exception.EsignDemoException; +import org.apache.http.*; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.HttpRequestRetryHandler; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.ConnectTimeoutException; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.LayeredConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.protocol.HttpContext; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.*; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.UnknownHostException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * @author 澄泓 + * @description Http请求 辅助类 + * @since JDK1.7 + */ +public class EsignHttpCfgHelper { + + private static final Logger LOGGER = LoggerFactory.getLogger(EsignHttpCfgHelper.class); + /** + * 超时时间,默认15000毫秒 + */ + private static int MAX_TIMEOUT = 15000; + /** + * 请求池最大连接数,默认100个 + */ + private static int MAX_TOTAL = 100; + /** + * 单域名最大的连接数,默认50个 + */ + private static int ROUTE_MAX_TOTAL = 50; + /** + * 请求失败重试次数,默认3次 + */ + private static int MAX_RETRY = 3; + /** + * 是否需要域名校验,默认不需要校验 + */ + private static boolean SSL_VERIFY = false; + + /** + * 正向代理IP + */ + private static String PROXY_IP; + /** + * 正向代理端口,默认8888 + */ + private static int PROXY_PORT = 8888; + /** + * 代理协议,默认http + */ + private static String PROXY_AGREEMENT = "http"; + + /** + * 是否开启代理,默认false + */ + private static boolean OPEN_PROXY = false; + + /** + * 代理服务器用户名 + */ + private static String PROXY_USERNAME = ""; + + /** + * 代理服务器密码 + */ + private static String PROXY_PASSWORD = ""; + + + private static PoolingHttpClientConnectionManager connMgr; //连接池 + private static HttpRequestRetryHandler retryHandler; //重试机制 + + private static CloseableHttpClient httpClient = null; + + /** + * 不允许外部创建实例 + */ + private EsignHttpCfgHelper() { + } + + public static int getMaxTimeout() { + return MAX_TIMEOUT; + } + + public static void setMaxTimeout(int maxTimeout) { + MAX_TIMEOUT = maxTimeout; + } + + public static int getMaxTotal() { + return MAX_TOTAL; + } + + public static void setMaxTotal(int maxTotal) { + MAX_TOTAL = maxTotal; + } + + public static int getRouteMaxTotal() { + return ROUTE_MAX_TOTAL; + } + + public static void setRouteMaxTotal(int routeMaxTotal) { + ROUTE_MAX_TOTAL = routeMaxTotal; + } + + public static int getMaxRetry() { + return MAX_RETRY; + } + + public static void setMaxRetry(int maxRetry) { + MAX_RETRY = maxRetry; + } + + public static boolean isSslVerify() { + return SSL_VERIFY; + } + + public static void setSslVerify(boolean sslVerify) { + SSL_VERIFY = sslVerify; + } + + public static String getProxyIp() { + return PROXY_IP; + } + + public static void setProxyIp(String proxyIp) { + PROXY_IP = proxyIp; + } + + public static int getProxyPort() { + return PROXY_PORT; + } + + public static void setProxyPort(int proxyPort) { + PROXY_PORT = proxyPort; + } + + public static String getProxyAgreement() { + return PROXY_AGREEMENT; + } + + public static void setProxyAgreement(String proxyAgreement) { + PROXY_AGREEMENT = proxyAgreement; + } + + public static boolean getOpenProxy() { + return OPEN_PROXY; + } + + public static void setOpenProxy(boolean openProxy) { + OPEN_PROXY = openProxy; + } + + public static String getProxyUsername() { + return PROXY_USERNAME; + } + + public static void setProxyUserame(String proxyUsername) { + PROXY_USERNAME = proxyUsername; + } + + public static String getProxyPassword() { + return PROXY_PASSWORD; + } + + public static void setProxyPassword(String proxyPassword) { + PROXY_PASSWORD = proxyPassword; + } + + //------------------------------公有方法start-------------------------------------------- + + /** + * @param reqType {@link EsignRequestType} 请求类型 GET、 POST 、 DELETE 、 PUT + * @param httpUrl {@link String} 请求目标地址 + * @param headers {@link Map} 请求头 + * @param param {@link Object} 参数 + * @return + * @throws EsignDemoException + * @description 发起HTTP / HTTPS 请求 + * @author 澄泓 + */ + public static EsignHttpResponse sendHttp(EsignRequestType reqType, String httpUrl, Map headers, Object param, boolean debug) + throws EsignDemoException { + HttpRequestBase reqBase = null; + if (httpUrl.startsWith("http")) { + reqBase = reqType.getHttpType(httpUrl); + } else { + throw new EsignDemoException("请求url地址格式错误"); + } + if (debug) { + LOGGER.info("请求头:{}", headers + "\n"); + LOGGER.info("请求参数\n{}", param + "\n"); + LOGGER.info("请求地址\n:{}\n请求方式\n:{}", reqBase.getURI(), reqType + "\n"); + } + //请求方法不是GET或者DELETE时传入body体,否则不传入。 + String[] methods = {"DELETE", "GET"}; + if (param instanceof String && Arrays.binarySearch(methods, reqType.name()) < 0) {//POST或者PUT请求 + ((HttpEntityEnclosingRequest) reqBase).setEntity( + new StringEntity(String.valueOf(param), ContentType.create("application/json", "UTF-8"))); + } + //参数时字节流数组 + else if (param instanceof byte[]) { + reqBase = reqType.getHttpType(httpUrl); + byte[] paramBytes = (byte[]) param; + ((HttpEntityEnclosingRequest) reqBase).setEntity(new ByteArrayEntity(paramBytes)); + } + //参数是form表单时 + else if (param instanceof List) { + ((HttpEntityEnclosingRequest) reqBase).setEntity(new UrlEncodedFormEntity((Iterable) param)); + } + httpClient = getHttpClient(); + config(reqBase); + + //设置请求头 + if (headers != null && headers.size() > 0) { + for (Map.Entry entry : headers.entrySet()) { + reqBase.setHeader(entry.getKey(), entry.getValue()); + } + } + //响应对象 + CloseableHttpResponse res = null; + //响应内容 + String resCtx = null; + int status; + EsignHttpResponse esignHttpResponse = new EsignHttpResponse(); + try { + //执行请求 + res = httpClient.execute(reqBase); + status = res.getStatusLine().getStatusCode(); + + //获取请求响应对象和响应entity + HttpEntity httpEntity = res.getEntity(); + if (httpEntity != null) { + resCtx = EntityUtils.toString(httpEntity, "utf-8"); + } + if (debug) { + LOGGER.info("响应\n{}", resCtx + "\n"); + LOGGER.info("----------------------------end------------------------"); + } + } catch (NoHttpResponseException e) { + throw new EsignDemoException("服务器丢失了", e); + } catch (SSLHandshakeException e) { + String msg = MessageFormat.format("SSL握手异常", e); + EsignDemoException ex = new EsignDemoException(msg, e); + throw ex; + } catch (UnknownHostException e) { + EsignDemoException ex = new EsignDemoException("服务器找不到", e); + ex.initCause(e); + throw ex; + } catch (ConnectTimeoutException e) { + EsignDemoException ex = new EsignDemoException("连接超时", e); + ex.initCause(e); + throw ex; + } catch (SSLException e) { + EsignDemoException ex = new EsignDemoException("SSL异常", e); + ex.initCause(e); + throw ex; + } catch (ClientProtocolException e) { + EsignDemoException ex = new EsignDemoException("请求头异常", e); + ex.initCause(e); + throw ex; + } catch (IOException e) { + EsignDemoException ex = new EsignDemoException("网络请求失败", e); + ex.initCause(e); + throw ex; + } finally { + if (res != null) { + try { + res.close(); + } catch (IOException e) { + EsignDemoException ex = new EsignDemoException("--->>关闭请求响应失败", e); + ex.initCause(e); + throw ex; + } + } + } + esignHttpResponse.setStatus(status); + esignHttpResponse.setBody(resCtx); + return esignHttpResponse; + } + //------------------------------公有方法end---------------------------------------------- + + //------------------------------私有方法start-------------------------------------------- + + /** + * @param httpReqBase + * @description 请求头和超时时间配置 + * @author 澄泓 + */ + private static void config(HttpRequestBase httpReqBase) { + // 配置请求的超时设置 + RequestConfig.Builder builder = RequestConfig.custom() + .setConnectionRequestTimeout(MAX_TIMEOUT) + .setConnectTimeout(MAX_TIMEOUT) + .setSocketTimeout(MAX_TIMEOUT); + if (OPEN_PROXY) { + HttpHost proxy = new HttpHost(PROXY_IP, PROXY_PORT, PROXY_AGREEMENT); + builder.setProxy(proxy); + } + RequestConfig requestConfig = builder.build(); + httpReqBase.setConfig(requestConfig); + } + + /** + * @return + * @description 连接池配置 + * @author 澄泓 + */ + private static void cfgPoolMgr() throws EsignDemoException { + ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory(); + LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory(); + if (!SSL_VERIFY) { + sslsf = sslConnectionSocketFactory(); + } + + Registry registry = RegistryBuilder.create() + .register("http", plainsf) + .register("https", sslsf) + .build(); + + //连接池管理器 + connMgr = new PoolingHttpClientConnectionManager(registry); + //请求池最大连接数 + connMgr.setMaxTotal(MAX_TOTAL); + //但域名最大的连接数 + connMgr.setDefaultMaxPerRoute(ROUTE_MAX_TOTAL); + } + + + /** + * @description 设置重试机制 + * @author 澄泓 + */ + private static void cfgRetryHandler() { + retryHandler = new HttpRequestRetryHandler() { + + @Override + public boolean retryRequest(IOException e, int excCount, HttpContext ctx) { + //超过最大重试次数,就放弃 + if (excCount > MAX_RETRY) { + return false; + } + //服务器丢掉了链接,就重试 + if (e instanceof NoHttpResponseException) { + return true; + } + //不重试SSL握手异常 + if (e instanceof SSLHandshakeException) { + return false; + } + //中断 + if (e instanceof InterruptedIOException) { + return false; + } + //目标服务器不可达 + if (e instanceof UnknownHostException) { + return false; + } + //连接超时 + //SSL异常 + if (e instanceof SSLException) { + return false; + } + + HttpClientContext clientCtx = HttpClientContext.adapt(ctx); + HttpRequest req = clientCtx.getRequest(); + //如果是幂等请求,就再次尝试 + return !(req instanceof HttpEntityEnclosingRequest); + } + }; + } + + /** + * 忽略域名校验 + */ + private static SSLConnectionSocketFactory sslConnectionSocketFactory() throws EsignDemoException { + try { + SSLContext ctx = SSLContext.getInstance("TLS"); // 创建一个上下文(此处指定的协议类型似乎不是重点) + X509TrustManager tm = new X509TrustManager() { // 创建一个跳过SSL证书的策略 + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + } + + public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + } + }; + ctx.init(null, new TrustManager[]{tm}, null); // 使用上面的策略初始化上下文 + return new SSLConnectionSocketFactory(ctx, new String[]{"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}, null, NoopHostnameVerifier.INSTANCE); + } catch (Exception e) { + EsignDemoException ex = new EsignDemoException("忽略域名校验失败", e); + ex.initCause(e); + throw ex; + } + + } + + /** + * @return + * @description 获取单例HttpClient + * @author 澄泓 + */ + private static synchronized CloseableHttpClient getHttpClient() throws EsignDemoException { + if (httpClient == null) { + CredentialsProvider credsProvider = new BasicCredentialsProvider(); + credsProvider.setCredentials(new AuthScope(PROXY_IP, PROXY_PORT), new UsernamePasswordCredentials(PROXY_USERNAME, PROXY_PASSWORD)); + cfgPoolMgr(); + cfgRetryHandler(); + HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); + httpClient = httpClientBuilder.setDefaultCredentialsProvider(credsProvider).setConnectionManager(connMgr).setRetryHandler(retryHandler).build(); + } + return httpClient; + + } + //------------------------------私有方法end---------------------------------------------- + + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignHttpHelper.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignHttpHelper.java new file mode 100644 index 00000000..c3e4753f --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignHttpHelper.java @@ -0,0 +1,167 @@ +package com.suisung.mall.shop.esign.utils.comm; + +import com.suisung.mall.shop.esign.utils.enums.EsignHeaderConstant; +import com.suisung.mall.shop.esign.utils.enums.EsignRequestType; +import com.suisung.mall.shop.esign.utils.exception.EsignDemoException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author 澄泓 + * @description Http 请求 辅助类 + * @since JDK1.7 + */ +public class EsignHttpHelper { + private static final Logger LOGGER = LoggerFactory.getLogger(EsignHttpHelper.class); + + /** + * 不允许外部创建实例 + */ + private EsignHttpHelper() { + + } + + /** + * @param reqType 请求方式 + * @param url 请求路径 + * @param paramStr 请求参数 + * @return + * @throws EsignDemoException + * @description 发送常规HTTP 请求 + * @author 澄泓 + */ + public static EsignHttpResponse doCommHttp(String host, String url, EsignRequestType reqType, Object paramStr, Map httpHeader, boolean debug) throws EsignDemoException { + return EsignHttpCfgHelper.sendHttp(reqType, host + url, httpHeader, paramStr, debug); + } + + + /** + * @param reqType 请求方式 + * @param uploadUrl 请求路径 + * @param param 请求参数 + * @param fileContentMd5 文件fileContentMd5 + * @param contentType 文件MIME类型 + * @return + * @throws EsignDemoException + * @description 发送文件流上传 HTTP 请求 + * @author 澄泓 + */ + public static EsignHttpResponse doUploadHttp(String uploadUrl, EsignRequestType reqType, byte[] param, String fileContentMd5, + String contentType, boolean debug) throws EsignDemoException { + Map uploadHeader = buildUploadHeader(fileContentMd5, contentType); + if (debug) { + LOGGER.info("----------------------------start------------------------"); + LOGGER.info("fileContentMd5:{}", fileContentMd5); + LOGGER.info("contentType:{}", contentType); + } + return EsignHttpCfgHelper.sendHttp(reqType, uploadUrl, uploadHeader, param, debug); + } + + + /** + * @return + * @description 构建一个签名鉴权+json数据的esign请求头 + * @author 澄泓 + */ + public static Map buildSignAndJsonHeader(String projectId, String contentMD5, String accept, String contentType, String authMode) { + + Map header = new HashMap<>(); + header.put("X-Tsign-Open-App-Id", projectId); + header.put("X-Tsign-Open-Version-Sdk", EsignCoreSdkInfo.getSdkVersion()); + header.put("X-Tsign-Open-Ca-Timestamp", EsignEncryption.timeStamp()); + header.put("Accept", accept); + header.put("Content-MD5", contentMD5); + header.put("Content-Type", contentType); + header.put("X-Tsign-Open-Auth-Mode", authMode); + return header; + } + + /** + * 签名计算并且构建一个签名鉴权+json数据的esign请求头 + * + * @param httpMethod * The name of a supported {@linkplain java.nio.charset.Charset + * * charset} + * @return + */ + public static Map signAndBuildSignAndJsonHeader(String projectId, String secret, String paramStr, String httpMethod, String url, boolean debug) throws EsignDemoException { + String contentMD5 = ""; + //统一转大写处理 + httpMethod = httpMethod.toUpperCase(); + if ("GET".equals(httpMethod) || "DELETE".equals(httpMethod)) { + paramStr = null; + contentMD5 = ""; + } else if ("PUT".equals(httpMethod) || "POST".equals(httpMethod)) { + //对body体做md5摘要 + contentMD5 = EsignEncryption.doContentMD5(paramStr); + } else { + throw new EsignDemoException(String.format("不支持的请求方法%s", httpMethod)); + } + //构造一个初步的请求头 + Map esignHeaderMap = buildSignAndJsonHeader(projectId, contentMD5, EsignHeaderConstant.ACCEPT.VALUE(), EsignHeaderConstant.CONTENTTYPE_JSON.VALUE(), EsignHeaderConstant.AUTHMODE.VALUE()); + //排序 + url = EsignEncryption.sortApiUrl(url); + //传入生成的bodyMd5,加上其他请求头部信息拼接成字符串 + String message = EsignEncryption.appendSignDataString(httpMethod, esignHeaderMap.get("Content-MD5"), esignHeaderMap.get("Accept"), esignHeaderMap.get("Content-Type"), esignHeaderMap.get("Headers"), esignHeaderMap.get("Date"), url); + //整体做sha256签名 + String reqSignature = EsignEncryption.doSignatureBase64(message, secret); + //请求头添加签名值 + esignHeaderMap.put("X-Tsign-Open-Ca-Signature", reqSignature); + if (debug) { + LOGGER.info("----------------------------start------------------------"); + LOGGER.info("待计算body值:{}", paramStr + "\n"); + LOGGER.info("MD5值:{}", contentMD5 + "\n"); + LOGGER.info("待签名字符串:{}", message + "\n"); + LOGGER.info("签名值:{}", reqSignature + "\n"); + } + return esignHeaderMap; + } + + + /** + * @return + * @description 构建一个Token鉴权+jsons数据的esign请求头 + * @author 澄泓 + */ + public static Map buildTokenAndJsonHeader(String appid, String token) { + Map esignHeader = new HashMap<>(); + esignHeader.put("X-Tsign-Open-Version-Sdk", EsignCoreSdkInfo.getSdkVersion()); + esignHeader.put("Content-Type", EsignHeaderConstant.CONTENTTYPE_JSON.VALUE()); + esignHeader.put("X-Tsign-Open-App-Id", appid); + esignHeader.put("X-Tsign-Open-Token", token); + return esignHeader; + } + + /** + * @return + * @description 构建一个form表单数据的esign请求头 + * @author 澄泓 + */ + public static Map buildFormDataHeader(String appid) { + Map esignHeader = new HashMap<>(); + esignHeader.put("X-Tsign-Open-Version-Sdk", EsignCoreSdkInfo.getSdkVersion()); + esignHeader.put("X-Tsign-Open-Authorization-Version", "v2"); + esignHeader.put("Content-Type", EsignHeaderConstant.CONTENTTYPE_FORMDATA.VALUE()); + esignHeader.put("X-Tsign-Open-App-Id", appid); + return esignHeader; + } + + /** + * @param fileContentMd5 + * @param contentType + * @return + * @description 创建文件流上传 请求头 + * @author 澄泓 + */ + public static Map buildUploadHeader(String fileContentMd5, String contentType) { + Map header = new HashMap<>(); + header.put("Content-MD5", fileContentMd5); + header.put("Content-Type", contentType); + + return header; + } + + // ------------------------------私有方法end---------------------------------------------- +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignHttpResponse.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignHttpResponse.java new file mode 100644 index 00000000..ab1a601d --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/EsignHttpResponse.java @@ -0,0 +1,28 @@ +package com.suisung.mall.shop.esign.utils.comm; + +/** + * 网络请求的response类 + * + * @author 澄泓 + * @date 2022/2/21 17:28 + */ +public class EsignHttpResponse { + private int status; + private String body; + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/FileTransformation.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/FileTransformation.java new file mode 100644 index 00000000..5aad888e --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/comm/FileTransformation.java @@ -0,0 +1,284 @@ +/* + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package com.suisung.mall.shop.esign.utils.comm; + +import com.suisung.mall.shop.esign.utils.exception.EsignDemoException; +import org.apache.commons.codec.binary.Base64; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.Map; + +/** + * @author 澄泓 + * @version JDK1.7 + * @description 文件转换类 + * @date 2020/10/26 10:47 + */ +public class FileTransformation { + + /** + * 传入本地文件路径转二进制byte + * + * @param srcFilePath 本地文件路径 + * @return + * @throws EsignDemoException + */ + public static byte[] fileToBytes(String srcFilePath) throws EsignDemoException { + return getBytes(srcFilePath); + } + + /** + * 图片转base64 + * + * @param filePath 本地文件路径 + * @return + * @throws EsignDemoException + */ + public static String fileToBase64(String filePath) throws EsignDemoException { + byte[] bytes; + String base64 = null; + bytes = fileToBytes(filePath); + base64 = Base64.encodeBase64String(bytes); + base64 = base64.replaceAll("\r\n", ""); + return base64; + } + + public static void main(String[] args) throws EsignDemoException { + System.out.println(getFileContentMD5("D:\\文档\\PLT2022-02124CT.pdf")); + } + + /*** + * 计算文件内容的Content-MD5 + * @param filePath 文件路径 + * @return + */ + public static String getFileContentMD5(String filePath) throws EsignDemoException { + // 获取文件MD5的二进制数组(128位) + byte[] bytes = getFileMD5Bytes128(filePath); + // 对文件MD5的二进制数组进行base64编码 + return Base64.encodeBase64String(bytes); + } + + /** + * 下载文件 + * + * @param httpUrl 网络文件地址url + * @return + */ + public static boolean downLoadFileByUrl(String httpUrl, String dir) throws EsignDemoException { + InputStream fis = null; + FileOutputStream fileOutputStream = null; + try { + URL url = new URL(httpUrl); + HttpURLConnection httpConn = (HttpURLConnection) url.openConnection(); + httpConn.connect(); + fis = httpConn.getInputStream(); + fileOutputStream = new FileOutputStream(new File(dir)); + byte[] md5Bytes = null; + + byte[] buffer = new byte[1024]; + int length = -1; + while ((length = fis.read(buffer, 0, 1024)) != -1) { + fileOutputStream.write(buffer, 0, length); + } + } catch (IOException e) { + EsignDemoException ex = new EsignDemoException("获取文件流异常", e); + ex.initCause(e); + throw ex; + } finally { + try { + if (fis != null) { + fis.close(); + } + if (fileOutputStream != null) { + fileOutputStream.close(); + } + } catch (IOException e) { + EsignDemoException ex = new EsignDemoException("关闭文件流异常", e); + ex.initCause(e); + throw ex; + } + } + return true; + } + + + /** + * 网络文件转二进制MD5数组并获取文件大小 + * + * @param fileUrl 网络文件地址url + * @return + */ + public static Map fileUrlToBytes(String fileUrl) throws EsignDemoException { + HashMap map = new HashMap(); + try { + URL url = new URL(fileUrl); + HttpURLConnection httpConn = (HttpURLConnection) url.openConnection(); + httpConn.connect(); + InputStream fis = httpConn.getInputStream(); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + outStream.close(); + map.put("fileSize", fis.available()); + byte[] md5Bytes = null; + MessageDigest md5 = MessageDigest.getInstance("MD5"); + byte[] buffer = new byte[1024]; + int length = -1; + while ((length = fis.read(buffer, 0, 1024)) != -1) { + md5.update(buffer, 0, length); + outStream.write(buffer, 0, length); + } + md5Bytes = md5.digest(); + byte[] fileData = outStream.toByteArray(); + map.put("fileData", fileData); + outStream.close(); + fis.close(); + map.put("md5Bytes", md5Bytes); + } catch (IOException e) { + EsignDemoException ex = new EsignDemoException("获取文件流异常", e); + ex.initCause(e); + throw ex; + } catch (NoSuchAlgorithmException e) { + EsignDemoException ex = new EsignDemoException("文件计算异常", e); + ex.initCause(e); + throw ex; + } + return map; + } + + /*** + * 获取文件MD5的二进制数组(128位) + * @param filePath + * @return + * @throws EsignDemoException + */ + public static byte[] getFileMD5Bytes128(String filePath) throws EsignDemoException { + FileInputStream fis = null; + byte[] md5Bytes = null; + try { + File file = new File(filePath); + fis = new FileInputStream(file); + MessageDigest md5 = MessageDigest.getInstance("MD5"); + byte[] buffer = new byte[1024]; + int length = -1; + while ((length = fis.read(buffer, 0, 1024)) != -1) { + md5.update(buffer, 0, length); + } + md5Bytes = md5.digest(); + fis.close(); + } catch (FileNotFoundException e) { + EsignDemoException ex = new EsignDemoException("文件找不到", e); + ex.initCause(e); + throw ex; + } catch (NoSuchAlgorithmException e) { + EsignDemoException ex = new EsignDemoException("不支持此算法", e); + ex.initCause(e); + throw ex; + } catch (IOException e) { + EsignDemoException ex = new EsignDemoException("输入流或输出流异常", e); + ex.initCause(e); + throw ex; + } finally { + if (fis != null) { + try { + fis.close(); + } catch (IOException e) { + EsignDemoException ex = new EsignDemoException("关闭文件输入流失败", e); + ex.initCause(e); + throw ex; + } + } + } + return md5Bytes; + } + + /** + * @param path + * @return + * @throws EsignDemoException + * @description 根据文件路径,获取文件base64 + * @author 宫清 + * @date 2019年7月21日 下午4:22:08 + */ + public static String getBase64Str(String path) throws EsignDemoException { + InputStream is = null; + try { + is = new FileInputStream(new File(path)); + byte[] bytes = new byte[is.available()]; + is.read(bytes); + return Base64.encodeBase64String(bytes); + } catch (Exception e) { + EsignDemoException ex = new EsignDemoException("获取文件输入流失败", e); + ex.initCause(e); + throw ex; + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + EsignDemoException ex = new EsignDemoException("关闭文件输入流失败", e); + ex.initCause(e); + throw ex; + } + } + } + } + + /** + * @param path 文件路径 + * @return + * @description 获取文件名称 + * @author 宫清 + * @date 2019年7月21日 下午8:21:16 + */ + public static String getFileName(String path) { + return new File(path).getName(); + } + + /** + * @param filePath {@link String} 文件地址 + * @return + * @throws EsignDemoException + * @description 获取文件字节流 + * @date 2019年7月10日 上午9:17:00 + * @author 宫清 + */ + public static byte[] getBytes(String filePath) throws EsignDemoException { + File file = new File(filePath); + FileInputStream fis = null; + byte[] buffer = null; + try { + fis = new FileInputStream(file); + buffer = new byte[(int) file.length()]; + fis.read(buffer); + } catch (Exception e) { + EsignDemoException ex = new EsignDemoException("获取文件字节流失败", e); + ex.initCause(e); + throw ex; + } finally { + if (fis != null) { + try { + fis.close(); + } catch (IOException e) { + EsignDemoException ex = new EsignDemoException("关闭文件字节流失败", e); + ex.initCause(e); + throw ex; + } + } + } + return buffer; + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/enums/EsignHeaderConstant.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/enums/EsignHeaderConstant.java new file mode 100644 index 00000000..684186de --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/enums/EsignHeaderConstant.java @@ -0,0 +1,28 @@ +package com.suisung.mall.shop.esign.utils.enums; + +/** + * @author 澄泓 + * @version JDK1.7 + * @description 头部信息常量 + * @date 2020/10/22 15:05 + */ +public enum EsignHeaderConstant { + ACCEPT("*/*"), + DATE(""), + HEADERS(""), + CONTENTTYPE_FORMDATA("application/x-www-form-urlencoded"), + CONTENTTYPE_JSON("application/json; charset=UTF-8"), + CONTENTTYPE_PDF("application/pdf"), + CONTENTTYPE_STREAM("application/octet-stream"), + AUTHMODE("Signature"); + + private final String value; + + EsignHeaderConstant(String value) { + this.value = value; + } + + public String VALUE() { + return this.value; + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/enums/EsignRequestType.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/enums/EsignRequestType.java new file mode 100644 index 00000000..bcaed35a --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/enums/EsignRequestType.java @@ -0,0 +1,39 @@ +package com.suisung.mall.shop.esign.utils.enums; + +import org.apache.http.client.methods.*; + +/** + * @author 澄泓 + * @description 请求类型 + * @since JDK1.7 + */ +public enum EsignRequestType { + + POST { + @Override + public HttpRequestBase getHttpType(String url) { + return new HttpPost(url); + } + }, + GET { + @Override + public HttpRequestBase getHttpType(String url) { + return new HttpGet(url); + } + }, + DELETE { + @Override + public HttpRequestBase getHttpType(String url) { + return new HttpDelete(url); + } + }, + PUT { + @Override + public HttpRequestBase getHttpType(String url) { + return new HttpPut(url); + } + }, + ; + + public abstract HttpRequestBase getHttpType(String url); +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/exception/EsignDemoException.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/exception/EsignDemoException.java new file mode 100644 index 00000000..7b9ebd47 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/utils/exception/EsignDemoException.java @@ -0,0 +1,35 @@ +package com.suisung.mall.shop.esign.utils.exception; + +/** + * description 自定义全局异常 + * + * @author 澄泓 + * datetime 2019年7月1日上午10:43:24 + */ +public class EsignDemoException extends Exception { + + private static final long serialVersionUID = 4359180081622082792L; + private Exception e; + + public EsignDemoException(String msg) { + super(msg); + } + + public EsignDemoException(String msg, Throwable cause) { + super(msg, cause); + } + + public EsignDemoException() { + + } + + public Exception getE() { + return e; + } + + public void setE(Exception e) { + this.e = e; + } + + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LklTkController.java b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LklTkController.java index 70eae3b7..a9f7d7fa 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LklTkController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/lakala/controller/LklTkController.java @@ -33,7 +33,7 @@ public class LklTkController extends BaseControllerImpl { } @ApiOperation(value = "请求获取token(商户进件)", notes = "请求获取token(商户进件)") - @RequestMapping(value = "/token", method = RequestMethod.POST) + @RequestMapping(value = "/token1", method = RequestMethod.POST) public String getLklTkAuthorization1() { return commonService.getLklTkAuthorization(); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/merch/controller/admin/ShopMerchEntryAdminController.java b/mall-shop/src/main/java/com/suisung/mall/shop/merch/controller/admin/ShopMerchEntryAdminController.java new file mode 100644 index 00000000..bfa07ccf --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/merch/controller/admin/ShopMerchEntryAdminController.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.merch.controller.admin; + +import cn.hutool.json.JSONObject; +import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.service.impl.BaseControllerImpl; +import com.suisung.mall.shop.merch.service.ShopMerchEntryService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@Api(tags = "店铺基础信息表") +@RestController +@RequestMapping("/admin/shop/merch") +public class ShopMerchEntryAdminController extends BaseControllerImpl { + + @Resource + private ShopMerchEntryService shopMerchEntryService; + + /** + * 商家申请入驻商城平台 + * + * @param shopMerchEntryJSON + * @return + */ + @ApiOperation(value = "后台-商家申请入驻分页列表", notes = "商家申请入驻分页列表") + @RequestMapping(value = "/list", method = RequestMethod.POST) + public CommonResult shopMerchEntryList(@RequestBody JSONObject shopMerchEntryJSON) { + return shopMerchEntryService.shopMerchEntryList(shopMerchEntryJSON.getStr("keyword"), shopMerchEntryJSON.getInt("page"), shopMerchEntryJSON.getInt("pageSize")); + } + + @ApiOperation(value = "后台-获取商家入驻资料详情", notes = "后台-获取商家入驻资料详情") + @RequestMapping(value = "/detail", method = RequestMethod.POST) + public CommonResult shopMerchEntryDetail(@RequestBody JSONObject jsonParam) { + return shopMerchEntryService.shopMerchEntryDetail(jsonParam.getLong("id"), "", null); + } + + @ApiOperation(value = "商家入驻审批", notes = "商家入驻审批") + @RequestMapping(value = "/approval", method = RequestMethod.POST) + public CommonResult shopMerchEntryApproval(@RequestBody JSONObject jsonParam) { + // approvalStatus 入驻商家的审批状态:1-已通过;2-未通过;3-待审核; + return shopMerchEntryService.shopMerchEntryApproval(jsonParam.getLong("id"), jsonParam.getInt("approvalStatus"), jsonParam.getStr("approvalRemark")); + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/merch/controller/mobile/ShopMerchEntryController.java b/mall-shop/src/main/java/com/suisung/mall/shop/merch/controller/mobile/ShopMerchEntryController.java new file mode 100644 index 00000000..18cb6797 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/merch/controller/mobile/ShopMerchEntryController.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.merch.controller.mobile; + +import cn.hutool.json.JSONObject; +import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.service.impl.BaseControllerImpl; +import com.suisung.mall.shop.merch.service.ShopMerchEntryService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; + +@Api(tags = "店铺基础信息表") +@RestController +@RequestMapping("/mobile/shop/merch") +public class ShopMerchEntryController extends BaseControllerImpl { + + @Resource + private ShopMerchEntryService shopMerchEntryService; + + + @ApiOperation(value = "店铺主营分类(类目)", notes = "店铺主营分类(类目)") + @RequestMapping(value = "/business/category", method = RequestMethod.POST) + public CommonResult shopStoreBusinessCategoryList() { + return shopMerchEntryService.storeBusinessCategoryList(); + } + + @ApiOperation(value = "商家申请入驻商城平台", notes = "商家申请入驻商城平台") + @RequestMapping(value = "/apply", method = RequestMethod.POST) + public CommonResult shopMerchEntryApply(@RequestBody JSONObject shopMerchEntryJSON) { + return shopMerchEntryService.shopMerchEntryApply(shopMerchEntryJSON); + } + + @ApiOperation(value = "获取商家入驻资料详情", notes = "获取商家入驻资料详情") + @RequestMapping(value = "/detail", method = RequestMethod.POST) + public CommonResult shopMerchEntryDetail(@RequestBody JSONObject jsonParam) { + // approvalStatus 入驻商家的审批状态:1-已通过;2-未通过;3-待审核; + List approvalStatusList = new ArrayList(); + approvalStatusList.add(2); + approvalStatusList.add(3); + return shopMerchEntryService.shopMerchEntryDetail(null, jsonParam.getStr("mobile"), approvalStatusList); + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/merch/mapper/ShopMerchEntryMapper.java b/mall-shop/src/main/java/com/suisung/mall/shop/merch/mapper/ShopMerchEntryMapper.java new file mode 100644 index 00000000..8f02968b --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/merch/mapper/ShopMerchEntryMapper.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.merch.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.suisung.mall.common.modules.merch.ShopMerchEntry; +import org.springframework.stereotype.Component; + +@Component +public interface ShopMerchEntryMapper extends BaseMapper { +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/merch/service/ShopMerchEntryService.java b/mall-shop/src/main/java/com/suisung/mall/shop/merch/service/ShopMerchEntryService.java new file mode 100644 index 00000000..f05b1797 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/merch/service/ShopMerchEntryService.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.merch.service; + +import cn.hutool.json.JSONObject; +import com.suisung.mall.common.api.CommonResult; + +import java.util.List; + +public interface ShopMerchEntryService { + + /** + * 获取店铺的经营类目列表 + * + * @return + */ + CommonResult storeBusinessCategoryList(); + + /** + * 商品入驻申请 + * + * @param shopMerchEntryJSON + * @return + */ + CommonResult shopMerchEntryApply(JSONObject shopMerchEntryJSON); + + /** + * 商家入驻申请列表 + * + * @param keyword + * @param pageIndex + * @param pageSize + * @return + */ + CommonResult shopMerchEntryList(String keyword, Integer pageIndex, Integer pageSize); + + /** + * 通过 mobile 申请手机号或自增 ID 获取商家入驻申请详情 + * + * @param recordId + * @param mobile + * @param approvalStatusList + * @return + */ + CommonResult shopMerchEntryDetail(Long recordId, String mobile, List approvalStatusList); + + /** + * 商家入驻审批 + * + * @param id + * @param approvalStatus + * @param approvalRemark + * @return + */ + CommonResult shopMerchEntryApproval(Long id, Integer approvalStatus, String approvalRemark); + + + /** + * 检查手机和营业执照是否已经申请过? + * + * @param mobile + * @param bizLicenseNumber + * @return + */ + Boolean isApplied(String mobile, String bizLicenseNumber); +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/merch/service/impl/ShopMerchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/merch/service/impl/ShopMerchEntryServiceImpl.java new file mode 100644 index 00000000..218c3157 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/merch/service/impl/ShopMerchEntryServiceImpl.java @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.merch.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.constant.CommonConstant; +import com.suisung.mall.common.modules.merch.ShopMerchEntry; +import com.suisung.mall.common.utils.StringUtils; +import com.suisung.mall.common.utils.phone.PhoneNumberUtils; +import com.suisung.mall.core.web.service.impl.BaseServiceImpl; +import com.suisung.mall.shop.base.service.AccountBaseConfigService; +import com.suisung.mall.shop.merch.mapper.ShopMerchEntryMapper; +import com.suisung.mall.shop.merch.service.ShopMerchEntryService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +@Slf4j +@Service +public class ShopMerchEntryServiceImpl extends BaseServiceImpl implements ShopMerchEntryService { + + @Resource + private AccountBaseConfigService accountBaseConfigService; + + /** + * 获取店铺的经营类目列表 + * + * @return + */ + @Override + public CommonResult storeBusinessCategoryList() { +// UserDto user = getCurrentUser(); +// if (user == null) { +// return CommonResult.failed("无权限操作!"); +// } + + String businessCategoryList = accountBaseConfigService.getConfig("shop_business_category"); + if (StrUtil.isBlank(businessCategoryList)) { + return CommonResult.success(new String[0]); + } + + JSONArray businessCategoryJSONObject = JSONUtil.parseArray(businessCategoryList); + if (businessCategoryJSONObject == null) { + return CommonResult.success(new String[0]); + } + + return CommonResult.success(businessCategoryJSONObject); + } + + /** + * 商品入驻申请 + * + * @param shopMerchEntryJSON + * @return + */ + @Override + public CommonResult shopMerchEntryApply(JSONObject shopMerchEntryJSON) { + // 检查是否已登录? + String userId = "0"; + +// UserDto user = getCurrentUser(); +// if (user == null || user.getId() == null) { +// return CommonResult.failed("请先登录!"); +// } +// userId = user.getId().toString(); + + // 参数校验流程 + if (shopMerchEntryJSON == null) { + return CommonResult.failed("缺少必要参数!"); + } + + ShopMerchEntry record = JSONUtil.toBean(shopMerchEntryJSON, ShopMerchEntry.class); + if (record == null || StrUtil.isBlank(record.getLogin_mobile())) { + log.error("###商家入驻参数转换失败###"); + return CommonResult.failed("缺少必要参数!"); + } + + if (StrUtil.isBlank(record.getStore_name()) || StrUtil.isBlank(record.getStore_address()) + || StrUtil.isBlank(record.getStore_longitude()) + || StrUtil.isBlank(record.getStore_latitude())) { + return CommonResult.failed("缺少店铺名或详细地址!"); + } + + if (ObjectUtil.isEmpty(record.getBiz_category())) { + return CommonResult.failed("请选择经营品类!"); + } + + if (ObjectUtil.isEmpty(record.getContact_name())) { + return CommonResult.failed("请填写联系人!"); + } + + // 校验身份证,手机号格式 + if (StrUtil.isNotBlank(record.getLegal_person_id_number()) && !StringUtils.validateIDCard(record.getLegal_person_id_number())) { + return CommonResult.failed("法人身份证号码有误!"); + } + + if (StrUtil.isNotBlank(record.getIndividual_id_number()) && !StringUtils.validateIDCard(record.getIndividual_id_number())) { + return CommonResult.failed("个人身份证号码有误!"); + } + + if (StrUtil.isNotBlank(record.getLogin_mobile())) { +// String mobile = StrUtil.startWith(record.getLogin_mobile(), "+") ? record.getLogin_mobile() : CommonConstant.IDD_ZH_CN + record.getLogin_mobile(); + if (!PhoneNumberUtils.checkPhoneNumber(record.getLogin_mobile())) { + return CommonResult.failed("申请人手机号码有误!"); + } + } + + if (StrUtil.isNotBlank(record.getLegal_person_mobile())) { +// String mobile = StrUtil.startWith(record.getLegal_person_mobile(), "+") ? record.getLegal_person_mobile() : CommonConstant.IDD_ZH_CN + record.getLegal_person_mobile(); + if (!PhoneNumberUtils.checkPhoneNumber(record.getLegal_person_mobile())) { + return CommonResult.failed("法人手机号码有误!"); + } + } + + // 检查企业、法人或个人的营业执照或身份证 + if (ObjectUtil.isNotEmpty(record.getEntity_type()) && record.getEntity_type().equals(2)) { + // 个人 + if (StrUtil.isBlank(record.getIndividual_id_number()) || StrUtil.isBlank(record.getIndividual_id_images()) || StrUtil.isBlank(record.getIndividual_id_images2())) { + return CommonResult.failed("缺少个人身份证信息!"); + } + + } else { + // 企业 + if (StrUtil.isBlank(record.getBiz_license_number()) || StrUtil.isBlank(record.getBiz_license_image())) { + return CommonResult.failed("缺少企业营业执照信息!"); + } + + if (StrUtil.isBlank(record.getLegal_person_id_images()) || StrUtil.isBlank(record.getLegal_person_id_images2())) { + return CommonResult.failed("缺少企业法人身份证信息!"); + } + } + + // 检查银行账号 + if (StrUtil.isBlank(record.getBank_name()) || StrUtil.isBlank(record.getAccount_number()) || StrUtil.isBlank(record.getAccount_holder_name())) { + return CommonResult.failed("缺少银行账号信息!"); + } + + // 检查店铺是否已经申请过入驻 + if (isApplied(record.getLogin_mobile(), record.getBiz_license_number())) { + return CommonResult.failed("您手机号或营业执照已经申请过入驻!"); + } + + record.setCreated_by(userId); + record.setStatus(CommonConstant.Enable); + if (!add(record)) { + return CommonResult.failed("入驻信息提交失败!"); + } + + return CommonResult.success(); + } + + /** + * 商家入驻申请列表 + * + * @param keyword + * @param pageIndex + * @param pageSize + * @return + */ + @Override + public CommonResult shopMerchEntryList(String keyword, Integer pageIndex, Integer pageSize) { + // 检查登录用户是否有管理权限 +// UserDto user = getCurrentUser(); +// if (!user.isAdmin()) { +// return CommonResult.failed("权限不足!"); +// } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (StrUtil.isNotBlank(keyword)) { + queryWrapper.like("store_name", keyword); + } + + queryWrapper.orderByDesc("id"); + + if (ObjectUtil.isEmpty(pageIndex)) { + pageIndex = 1; + } + + if (ObjectUtil.isEmpty(pageSize)) { + pageSize = 20; + } + + Page listPage = lists(queryWrapper, pageIndex, pageSize); + + return CommonResult.success(listPage); + } + + /** + * 通过 mobile 申请手机号或自增 ID 获取商家入驻申请详情 + * + * @param recordId + * @param mobile + * @param approvalStatusList + * @return + */ + @Override + public CommonResult shopMerchEntryDetail(Long recordId, String mobile, List approvalStatusList) { + // 检查登录用户是否有管理权限或者是用户自己 + + // approvalStatus 入驻商家的审批状态:1-已通过;2-未通过;3-待审核; + if (ObjectUtil.isEmpty(recordId) && StrUtil.isBlank(mobile)) { + return CommonResult.failed("缺少必要参数!"); + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (ObjectUtil.isNotEmpty(recordId)) { + queryWrapper.eq("id", recordId); + } + + + if (StrUtil.isNotBlank(mobile)) { + queryWrapper.eq("login_mobile", mobile); + } + + if (CollectionUtil.isNotEmpty(approvalStatusList)) { + queryWrapper.in("approval_status", approvalStatusList); + } + queryWrapper.orderByDesc("id"); + List recordList = list(queryWrapper); + if (CollectionUtil.isEmpty(recordList)) { + return CommonResult.success(null, "暂无申请记录!"); + } + + return CommonResult.success(recordList.get(0)); + } + + /** + * 商家入驻审批 + * + * @param id + * @param approvalStatus + * @param approvalRemark + * @return + */ + @Override + public CommonResult shopMerchEntryApproval(Long id, Integer approvalStatus, String approvalRemark) { + // 检查登录用户是否有管理权限 + String userId = "0"; + +// UserDto user = getCurrentUser(); +// if (!user.isAdmin()) { +// return CommonResult.failed("权限不足!"); +// } +// userId = user.getId().toString(); + + if (ObjectUtil.isEmpty(id) || ObjectUtil.isEmpty(approvalStatus)) { + return CommonResult.failed("缺少必要参数!"); + } + + if (!approvalStatus.equals(1) && !approvalStatus.equals(2)) { + return CommonResult.failed("审批状态有误!"); + } + + if (approvalStatus.equals(1) && StrUtil.isBlank(approvalRemark)) { + approvalRemark = "审核通过,后续将到签署电子合同流程。"; + } else if (approvalStatus.equals(2) && StrUtil.isBlank(approvalRemark)) { + approvalRemark = "审核未通过,申请材料有待完善。"; + } + + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("id", id).set("approval_status", approvalStatus) + .set("approval_remark", approvalRemark) + .set("updated_by", userId); + + if (!update(updateWrapper)) { + return CommonResult.failed("审批出错,请联系管理员!"); + } + + return CommonResult.success(); + } + + /** + * 检查手机和营业执照是否已经申请过? + * + * @param mobile + * @param bizLicenseNumber + * @return + */ + @Override + public Boolean isApplied(String mobile, String bizLicenseNumber) { + if (StrUtil.isBlank(mobile) || StrUtil.isBlank(bizLicenseNumber)) { + return true; + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (StrUtil.isNotBlank(mobile)) { + queryWrapper.eq("login_mobile", mobile); + } + + if (StrUtil.isNotBlank(mobile)) { + queryWrapper.eq("biz_license_number", bizLicenseNumber); + } + + return count(queryWrapper) > 0; + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreSameCityTransportBaseServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreSameCityTransportBaseServiceImpl.java index cdc989db..3149569b 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreSameCityTransportBaseServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreSameCityTransportBaseServiceImpl.java @@ -13,6 +13,8 @@ import cn.hutool.core.comparator.FieldsComparator; import cn.hutool.core.convert.Convert; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.api.ResultCode; @@ -23,13 +25,13 @@ import com.suisung.mall.common.modules.store.ShopStoreBase; import com.suisung.mall.common.modules.store.ShopStoreSameCityTransport; import com.suisung.mall.common.modules.store.ShopStoreSameCityTransportBase; import com.suisung.mall.common.pojo.dto.DeliveryFeeResultDTO; -import com.suisung.mall.common.pojo.dto.KeyValueDTO; import com.suisung.mall.common.pojo.dto.SameCityDeliveryFeeRespDTO; import com.suisung.mall.common.pojo.dto.ShopStoreSameCityTransportBaseDTO; import com.suisung.mall.common.utils.CommonUtil; import com.suisung.mall.common.utils.I18nUtil; import com.suisung.mall.common.utils.PositionUtil; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; +import com.suisung.mall.shop.base.service.AccountBaseConfigService; import com.suisung.mall.shop.store.mapper.ShopStoreSameCityTransportBaseMapper; import com.suisung.mall.shop.store.service.ShopStoreBaseService; import com.suisung.mall.shop.store.service.ShopStoreSameCityTransportBaseService; @@ -59,6 +61,8 @@ public class ShopStoreSameCityTransportBaseServiceImpl extends BaseServiceImpl list = new ArrayList() {{ - add(new KeyValueDTO(1, "快餐")); - add(new KeyValueDTO(2, "药品")); - add(new KeyValueDTO(3, "百货")); - add(new KeyValueDTO(4, "脏衣服收")); - add(new KeyValueDTO(5, "干净衣服派")); - add(new KeyValueDTO(6, "生鲜")); - add(new KeyValueDTO(8, "高端饮品")); - add(new KeyValueDTO(10, "快递")); - add(new KeyValueDTO(12, "文件")); - add(new KeyValueDTO(13, "蛋糕")); - add(new KeyValueDTO(14, "鲜花")); - add(new KeyValueDTO(15, "数码")); - add(new KeyValueDTO(16, "服装")); - add(new KeyValueDTO(17, "汽配")); - add(new KeyValueDTO(18, "珠宝")); - add(new KeyValueDTO(20, "披萨")); - add(new KeyValueDTO(21, "中餐")); - add(new KeyValueDTO(22, "水产")); - add(new KeyValueDTO(32, "中端饮品")); - add(new KeyValueDTO(33, "便利店")); - add(new KeyValueDTO(34, "面包糕点")); - add(new KeyValueDTO(35, "火锅")); - add(new KeyValueDTO(36, "证照")); - add(new KeyValueDTO(40, "烧烤小龙虾")); - add(new KeyValueDTO(41, "外部落地配")); - add(new KeyValueDTO(44, "年夜饭")); - add(new KeyValueDTO(47, "烟酒行")); - add(new KeyValueDTO(48, "成人用品")); - add(new KeyValueDTO(53, "冷链医药")); - add(new KeyValueDTO(55, "宠物用品")); - add(new KeyValueDTO(56, "母婴用品")); - add(new KeyValueDTO(57, "美妆用品")); - add(new KeyValueDTO(58, "家居建材")); - add(new KeyValueDTO(59, "眼镜行")); - add(new KeyValueDTO(60, "图文广告")); - add(new KeyValueDTO(81, "中药")); - }}; + String businessCategoryList = accountBaseConfigService.getConfig("shop_business_category"); + if (StrUtil.isBlank(businessCategoryList)) { + return CommonResult.success(new String[0]); + } - return CommonResult.success(list, ""); + JSONObject businessCategoryJSONObject = JSONUtil.parseObj(businessCategoryList); + if (businessCategoryJSONObject == null) { + return CommonResult.success(new String[0]); + } + + return CommonResult.success(businessCategoryJSONObject); + +// +// +// List list = new ArrayList() {{ +// add(new KeyValueDTO(1, "快餐")); +// add(new KeyValueDTO(2, "药品")); +// add(new KeyValueDTO(3, "百货")); +// add(new KeyValueDTO(4, "脏衣服收")); +// add(new KeyValueDTO(5, "干净衣服派")); +// add(new KeyValueDTO(6, "生鲜")); +// add(new KeyValueDTO(8, "高端饮品")); +// add(new KeyValueDTO(10, "快递")); +// add(new KeyValueDTO(12, "文件")); +// add(new KeyValueDTO(13, "蛋糕")); +// add(new KeyValueDTO(14, "鲜花")); +// add(new KeyValueDTO(15, "数码")); +// add(new KeyValueDTO(16, "服装")); +// add(new KeyValueDTO(17, "汽配")); +// add(new KeyValueDTO(18, "珠宝")); +// add(new KeyValueDTO(20, "披萨")); +// add(new KeyValueDTO(21, "中餐")); +// add(new KeyValueDTO(22, "水产")); +// add(new KeyValueDTO(32, "中端饮品")); +// add(new KeyValueDTO(33, "便利店")); +// add(new KeyValueDTO(34, "面包糕点")); +// add(new KeyValueDTO(35, "火锅")); +// add(new KeyValueDTO(36, "证照")); +// add(new KeyValueDTO(40, "烧烤小龙虾")); +// add(new KeyValueDTO(41, "外部落地配")); +// add(new KeyValueDTO(44, "年夜饭")); +// add(new KeyValueDTO(47, "烟酒行")); +// add(new KeyValueDTO(48, "成人用品")); +// add(new KeyValueDTO(53, "冷链医药")); +// add(new KeyValueDTO(55, "宠物用品")); +// add(new KeyValueDTO(56, "母婴用品")); +// add(new KeyValueDTO(57, "美妆用品")); +// add(new KeyValueDTO(58, "家居建材")); +// add(new KeyValueDTO(59, "眼镜行")); +// add(new KeyValueDTO(60, "图文广告")); +// add(new KeyValueDTO(81, "中药")); +// }}; +// +// return CommonResult.success(list, ""); } /** diff --git a/mall-shop/src/main/resources/bootstrap-local.yml b/mall-shop/src/main/resources/bootstrap-local.yml index 5bf060d1..bbd357d4 100644 --- a/mall-shop/src/main/resources/bootstrap-local.yml +++ b/mall-shop/src/main/resources/bootstrap-local.yml @@ -145,4 +145,11 @@ lakala: client_id: lsycs client_secret: XPa1HB5d55Ig0qV8 api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt - api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt \ No newline at end of file + api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt +#e签宝配置 +esign: + server_url: https://smlopenapi.esign.cn + #正式地址 https://openapi.esign.cn + app_id: 7439053575 + app_secret: 8da2e1eeeaf88e09bcf432a2fdd3e4d7 + app_rsa: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiC+fUc0+O9m45VEcGciJQ5QQNXs3NkHoHM2qDAdrXOnTwku0Be1IPeWUZ4s7w8xqubyirAAJDc3LpRkwCK84NicA2VwraD4on8MNtX8MLALZjLc1jZTmRAPKVfTKAcainR7ET78Y+QKJgezNvI7u45FO4Db+dWCC7pbedxBo+kHKA8im+/G0hpQaklxw1wjIMNv+x+YBnm8FOXRPWJZ+eItF5qJOT2C16QCY7hdeHknom+NMpZD8E/WAMtf03BcgigsoavTVnPI0xnN8BCrgykDWgO5bUXeIgNEF1LJS6r8s6BaMl+ZWbuODtbsrQ941GbFOe6x8tnhPIeehIa1AWQIDAQAB diff --git a/mall-shop/src/main/resources/mapper/esign/EsignContractFillingFileMapper.xml b/mall-shop/src/main/resources/mapper/esign/EsignContractFillingFileMapper.xml new file mode 100644 index 00000000..87cf3504 --- /dev/null +++ b/mall-shop/src/main/resources/mapper/esign/EsignContractFillingFileMapper.xml @@ -0,0 +1,8 @@ + + + + + + * + + diff --git a/mall-shop/src/main/resources/mapper/merch/ShopMerchEntryMapper.xml b/mall-shop/src/main/resources/mapper/merch/ShopMerchEntryMapper.xml new file mode 100644 index 00000000..6f09d40a --- /dev/null +++ b/mall-shop/src/main/resources/mapper/merch/ShopMerchEntryMapper.xml @@ -0,0 +1,8 @@ + + + + + + * + +