This commit is contained in:
ran.shang
2025-12-29 16:06:48 +08:00
parent b853edcfde
commit ee95dfa2c2
1600 changed files with 6997 additions and 7445 deletions

View File

@@ -0,0 +1,29 @@
package com.senmesh.sdk.ai.config;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = AiProperties.PREFIX)
@Data
@Component
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AiProperties implements Serializable{
/** **/
private static final long serialVersionUID = 6362606996602121889L;
public static final String PREFIX = "ai";
/** 对话提供者 **/
private String chatProvider;
}

View File

@@ -0,0 +1,37 @@
package com.senmesh.sdk.ai.service.service;
import com.senmesh.common.AlitaResult;
import com.senmesh.sdk.ai.config.AiProperties;
import com.senmesh.sdk.deepseek.service.DeepSeekProvider;
import com.senmesh.sdk.xf.config.XfProperties;
import com.senmesh.sdk.xf.model.ChatReq;
import com.senmesh.sdk.xf.service.XfSparkProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class AiProvider {
private static AiProperties aiProperties;
@Autowired
private DeepSeekProvider deepSeekProvider;
@Autowired
private XfSparkProvider xfSparkProvider;
private AiProvider(AiProperties aiProperties) {
AiProvider.aiProperties = aiProperties;
}
public static AlitaResult<String> httpChat(ChatReq req) {
if (aiProperties.getChatProvider().equals(XfProperties.PREFIX)) {
return XfSparkProvider.httpChat(req);
} else {
req.setModel("deepseek-chat");
return DeepSeekProvider.httpChat(req);
}
}
}

View File

@@ -0,0 +1,24 @@
package com.senmesh.sdk.ai.util;
import com.senmesh.common.AlitaResult;
import com.senmesh.common.exception.util.Assert;
import com.senmesh.sdk.ai.service.service.AiProvider;
import com.senmesh.sdk.xf.model.ChatReq;
import org.springframework.stereotype.Component;
@Component
public class AIUtils {
/**
* 对话
* @param req
* @return
*/
public static String chat(ChatReq req) {
AlitaResult<String> result = AiProvider.httpChat(req);
Assert.isTrue(result.getSuccess(), result.getMsg());
return result.getData();
}
}

View File

@@ -0,0 +1,44 @@
package com.senmesh.sdk.ali.config;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Builder.Default;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = AliProperties.PREFIX)
@Data
@Component
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AliProperties {
/** 配置前缀 */
public static final String PREFIX = "ali";
public static final String IDCARD_PREFIX = PREFIX + ".idcard";
/** 二要素配置 */
private IdcardProperties idcard;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class IdcardProperties {
/** 是否启用 **/
@Default
private Boolean enable = Boolean.FALSE;
/** 次数限制 **/
private Long numLimit;
private String url;
/** */
private String appcode;
}
}

View File

@@ -0,0 +1,27 @@
package com.senmesh.sdk.ali.dto;
import com.senmesh.sdk.common.dto.ISdkRequest;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.core.ParameterizedTypeReference;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class IdCardReq implements ISdkRequest<VerifyRes<IdCardRes>> {
private static ParameterizedTypeReference<VerifyRes<IdCardRes>> type = new ParameterizedTypeReference<VerifyRes<IdCardRes>>() {
};
private String name;
private String idcard;
@Override
public ParameterizedTypeReference<VerifyRes<IdCardRes>> getResponseType() {
return type;
}
}

View File

@@ -0,0 +1,27 @@
package com.senmesh.sdk.ali.dto;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class IdCardRes implements Serializable {
/** code为200 data才会有值,400参数格式错误 */
public static final Integer SUC_CODE = 200;
/** 1.不一致 0.一致 */
public static final Integer SUC_RESULT = 0;
private String birthday;
private Integer result;
private String address;
private String orderNo;
private String sex;
private String desc;
}

View File

@@ -0,0 +1,17 @@
package com.senmesh.sdk.ali.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class VerifyRes<T> {
private String msg;
private String success;
private Integer code;
private T data;
}

View File

@@ -0,0 +1,14 @@
package com.senmesh.sdk.ali.service;
import com.senmesh.common.AlitaResult;
import com.senmesh.sdk.ali.dto.IdCardReq;
import com.senmesh.sdk.ali.dto.IdCardRes;
public interface AliVerifyService {
String BEAN_ID = "sdk.aliVerifyService";
String MOCK_BEAN_ID = "mock.aliVerifyService";
AlitaResult<IdCardRes> verify(IdCardReq req);
}

View File

@@ -0,0 +1,78 @@
package com.senmesh.sdk.ali.service.impl;
import com.senmesh.common.AlitaResult;
import com.senmesh.common.annotation.CheckAndMock;
import com.senmesh.common.util.JsonUtils;
import com.senmesh.common.util.StrUtils;
import com.senmesh.sdk.ali.config.AliProperties;
import com.senmesh.sdk.ali.config.AliProperties.IdcardProperties;
import com.senmesh.sdk.ali.dto.IdCardReq;
import com.senmesh.sdk.ali.dto.IdCardRes;
import com.senmesh.sdk.ali.dto.VerifyRes;
import com.senmesh.sdk.ali.service.AliVerifyService;
import com.senmesh.sdk.common.constant.SdkConstants;
import com.senmesh.sdk.common.dto.DefaultSdkInvokeLogDTO;
import com.senmesh.sdk.common.util.HttpUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Slf4j
@Service(AliVerifyService.BEAN_ID)
public class AliVerifyServiceImpl implements AliVerifyService {
private static RestTemplate restTemplate = HttpUtils.restTemplate;
@Autowired
private AliProperties aliProperties;
@Override
@CheckAndMock(mockClass = MockAliVerifyServiceImpl.class,
propertyPrefix = AliProperties.IDCARD_PREFIX)
public AlitaResult<IdCardRes> verify(IdCardReq req){
return this.verify(req, aliProperties.getIdcard());
}
public static AlitaResult<IdCardRes> verify(IdCardReq req, IdcardProperties idcardProperties){
VerifyRes<IdCardRes> res = null;
try {
try {
// 构建请求头
HttpHeaders header = new HttpHeaders();
header.add("Authorization", "APPCODE " + idcardProperties.getAppcode());
header.add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
// 发送请求
HttpEntity<?> requestEntity = new HttpEntity(StrUtils.buildQueryValue(req), header);
ResponseEntity<VerifyRes<IdCardRes>> result = restTemplate.exchange(idcardProperties.getUrl(),
HttpMethod.POST, requestEntity, req.getResponseType());
res = result.getBody();
} catch (Exception e) {
log.info("invoke error :{}", e);
return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_ERROR_CODE, e.getMessage());
}
try {
if (IdCardRes.SUC_CODE.equals(res.getCode()) && IdCardRes.SUC_RESULT.equals(res.getData().getResult())) {
return AlitaResult.success(res.getData());
}
return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_RESPONSE_FAIL_CODE,
res.getData() == null ? res.getMsg() : res.getData().getDesc());
} catch (Exception e) {
return AlitaResult.error(SdkConstants.SDK_RESPONSE_CONVERT_ERROR_CODE,
e.getMessage());
}
} finally {
log.info("invoke:{}",
JsonUtils
.toJsonString(
DefaultSdkInvokeLogDTO.builder().requestData(req).responseData(res)
.build()));
}
}
}

View File

@@ -0,0 +1,19 @@
package com.senmesh.sdk.ali.service.impl;
import com.senmesh.common.AlitaResult;
import com.senmesh.sdk.ali.dto.IdCardReq;
import com.senmesh.sdk.ali.dto.IdCardRes;
import com.senmesh.sdk.ali.service.AliVerifyService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service(AliVerifyService.MOCK_BEAN_ID)
public class MockAliVerifyServiceImpl implements AliVerifyService {
@Override
public AlitaResult<IdCardRes> verify(IdCardReq req) {
log.info("ali idcard mock...");
return AlitaResult.success(IdCardRes.builder().result(IdCardRes.SUC_RESULT).build());
}
}

View File

@@ -0,0 +1,30 @@
package com.senmesh.sdk.bytedance;
import com.senmesh.common.AlitaResult;
import com.senmesh.sdk.bytedance.constant.ByteDanceConstants;
import com.senmesh.sdk.bytedance.model.BaseByteDanceDTO;
import com.senmesh.sdk.common.constant.SdkConstants;
import com.senmesh.sdk.common.dto.ISdkRequest;
import com.senmesh.sdk.common.exception.SdkException;
import com.senmesh.sdk.common.util.HttpUtils;
/**
* @author sr on 2021-11-25
*/
public class ByteDanceUtils {
public static <T> AlitaResult<T> execute(ISdkRequest<BaseByteDanceDTO<T>> req) {
try {
BaseByteDanceDTO<T> dto = HttpUtils.post(req);
Long errNo = dto.getErrNo();
if (ByteDanceConstants.SUCCESS_CODE.equals(errNo)) {
return AlitaResult.success(dto.getData());
}
return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_RESPONSE_FAIL_CODE,
dto.getErrNo() + dto.getErrTips());
} catch (SdkException e) {
return AlitaResult.error("字节接口调用失败:" + e.getMessage());
}
}
}

View File

@@ -0,0 +1,11 @@
package com.senmesh.sdk.bytedance.constant;
/**
* 字节常量
* @author sr on 2021-11-25
*/
public interface ByteDanceConstants {
Long SUCCESS_CODE = 0L;
}

View File

@@ -0,0 +1,25 @@
package com.senmesh.sdk.bytedance.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AccessTokenDataDTO {
/** **/
private static final long serialVersionUID = 814049874223007628L;
/** 接口调用凭证 **/
@JsonProperty("access_token")
private String accessToken;
/** access_token接口调用凭证超时时间,单位(秒) **/
@JsonProperty("expires_in")
private String expiresIn;
}

View File

@@ -0,0 +1,48 @@
package com.senmesh.sdk.bytedance.model;
import org.springframework.core.ParameterizedTypeReference;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.senmesh.common.annotation.Mask;
import com.senmesh.sdk.common.dto.ISdkRequest;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Builder.Default;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class AccessTokenReqDTO implements ISdkRequest<BaseByteDanceDTO<AccessTokenDataDTO>>{
/** **/
private static final long serialVersionUID = 197693764614332172L;
private static ParameterizedTypeReference<BaseByteDanceDTO<AccessTokenDataDTO>> type =
new ParameterizedTypeReference<BaseByteDanceDTO<AccessTokenDataDTO>>() {};
/** 第三方用户唯一凭证 **/
@JsonProperty("appid")
private String appId;
@Mask
/** 第三方用户唯一凭证密钥,即appsecret **/
private String secret;
@Default
@JsonProperty("grant_type")
private String grantType = "client_credential";
@Override
public String getUri() {
return "https://developer.toutiao.com/api/apps/v2/token";
}
@Override
public ParameterizedTypeReference<BaseByteDanceDTO<AccessTokenDataDTO>> getResponseType() {
return type;
}
}

View File

@@ -0,0 +1,23 @@
package com.senmesh.sdk.bytedance.model;
import lombok.Data;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.senmesh.sdk.common.dto.ISdkResponse;
@Data
public class BaseByteDanceDTO<T> implements ISdkResponse, Serializable {
/** 错误编码 **/
@JsonProperty("err_no")
private Long errNo;
/** 错误信息 **/
@JsonProperty("err_tips")
private String errTips;
private T data;
}

View File

@@ -0,0 +1,40 @@
package com.senmesh.sdk.bytedance.model;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author sr on 2021-11-25
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Code2SessionDataDTO implements Serializable {
/** **/
private static final long serialVersionUID = -5908915158294552716L;
/** 会话密钥,如果请求时有 code 参数才会返回 **/
@JsonProperty("session_key")
private String sessionKey;
/** 用户在当前小程序的 ID,如果请求时有 code 参数才会返回 **/
@JsonProperty("openid")
private String openId;
/** 匿名用户在当前小程序的 ID,如果请求时有 anonymous_code 参数才会返回 **/
@JsonProperty("anonymous_openid")
private String anonymousOpenId;
/** 用户在小程序平台的唯一标识符,请求时有 code 参数才会返回。如果开发者拥有多个小程序,可通过 unionid 来区分用户的唯一性 **/
@JsonProperty("unionid")
private String unionId;
}

View File

@@ -0,0 +1,49 @@
package com.senmesh.sdk.bytedance.model;
import org.springframework.core.ParameterizedTypeReference;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.senmesh.common.annotation.Mask;
import com.senmesh.sdk.common.dto.ISdkRequest;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Code2SessionReqDTO implements ISdkRequest<BaseByteDanceDTO<Code2SessionDataDTO>> {
/** **/
private static final long serialVersionUID = 197693764614332172L;
private static ParameterizedTypeReference<BaseByteDanceDTO<Code2SessionDataDTO>> type =
new ParameterizedTypeReference<BaseByteDanceDTO<Code2SessionDataDTO>>() {};
/** 第三方用户唯一凭证 **/
@JsonProperty("appid")
private String appId;
@Mask
/** 第三方用户唯一凭证密钥,即appsecret **/
private String secret;
/** login 接口返回的登录凭证 **/
private String code;
/** login 接口返回的匿名登录凭证 **/
@JsonProperty("anonymous_code")
private String anonymousCode;
@Override
public String getUri() {
return "https://developer.toutiao.com/api/apps/v2/jscode2session";
}
@Override
public ParameterizedTypeReference<BaseByteDanceDTO<Code2SessionDataDTO>> getResponseType() {
return type;
}
}

View File

@@ -0,0 +1,39 @@
package com.senmesh.sdk.captcha.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.senmesh.sdk.captcha.service.ITencentCaptchaService;
import com.senmesh.sdk.captcha.service.impl.LoginCaptchaAppProvider;
import com.senmesh.sdk.captcha.service.impl.TencentCaptchaServiceImpl;
import com.tencentcloudapi.common.Credential;
/**
* 验证码配置类
*
* @author sr on 2020-08-10
*/
@Configuration
@EnableConfigurationProperties({CaptchaProperties.class})
public class CaptchaConfiguration {
@Bean
@ConditionalOnProperty(havingValue = "true", name = "captcha.tencent.enable")
public ITencentCaptchaService tencentCaptchaService(CaptchaProperties captchaProperties) {
Credential credential = new Credential(captchaProperties.getTencent().getSecretId(),
captchaProperties.getTencent().getSecretKey());
return new TencentCaptchaServiceImpl(credential);
}
@Bean
@ConditionalOnBean(ITencentCaptchaService.class)
public LoginCaptchaAppProvider loginCaptchaAppProvider(
ITencentCaptchaService tencentCaptchaService, CaptchaProperties captchaProperties) {
return new LoginCaptchaAppProvider(tencentCaptchaService, captchaProperties);
}
}

View File

@@ -0,0 +1,23 @@
package com.senmesh.sdk.captcha.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 属性配置
*
* @author sr on 2020-08-10
*/
@ConfigurationProperties(prefix = CaptchaProperties.PREFIX)
@Data
@NoArgsConstructor
public class CaptchaProperties {
public static final String PREFIX = "captcha";
/** 腾讯配置 **/
private TencentProperties tencent;
}

View File

@@ -0,0 +1,18 @@
package com.senmesh.sdk.captcha.config;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 腾讯验证码应用配置
*
* @author sr on 2020-08-11
*/
@Data
@NoArgsConstructor
public class TencentAppProperties {
private String appId;
private String appSecret;
}

View File

@@ -0,0 +1,24 @@
package com.senmesh.sdk.captcha.config;
import java.util.HashMap;
import java.util.Map;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 腾讯配置
*
* @author sr on 2020-08-11
*/
@Data
@NoArgsConstructor
public class TencentProperties {
private Boolean enable;
private String secretId;
private String secretKey;
private final Map<String, TencentAppProperties> app = new HashMap<>();
}

View File

@@ -0,0 +1,57 @@
package com.senmesh.sdk.captcha.dto;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author sr on 2020-08-10
*/
@Data
@NoArgsConstructor
public class TencentCaptchaDTO implements Serializable{
/** **/
private static final long serialVersionUID = 2301105027025640174L;
/** 前端回调函数返回的用户验证票据(必填) **/
@JsonProperty("Ticket")
private String ticket;
/** 用户操作来源的外网 IP(可为空,前提是上下文request不为空) **/
@JsonProperty("UserIp")
private String userIp;
/** 前端回调函数返回的随机字符串(必填) **/
@JsonProperty("Randstr")
private String randstr;
/** 验证码应用ID;(可为空,配置文件获取) **/
@JsonProperty("CaptchaAppId")
private Long captchaAppId;
/** 用于服务器端校验验证码票据的验证密钥;(可为空,配置文件获取) **/
@JsonProperty("AppSecretKey")
private String appSecretKey;
/** 业务 ID,网站或应用在多个业务中使用此服务,通过此 ID 区分统计数据(可为空) **/
@JsonProperty("BusinessId")
private Long businessId;
/** 场景 ID,网站或应用的业务下有多个场景使用此服务,通过此 ID 区分统计数据(可为空)**/
@JsonProperty("SceneId")
private Long sceneId;
/** mac 地址或设备唯一标识(可为空) **/
@JsonProperty("MacAddress")
private String macAddress;
/** 手机设备号(可为空) **/
@JsonProperty("Imei")
private String imei;
/** 是否返回前端获取验证码时间,取值1:需要返回(可为空) **/
@JsonProperty("NeedGetCaptchaTime")
private Long needGetCaptchaTime;
public TencentCaptchaDTO(String ticket, String randstr) {
super();
this.ticket = ticket;
this.randstr = randstr;
}
}

View File

@@ -0,0 +1,29 @@
package com.senmesh.sdk.captcha.mapstruct;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import com.senmesh.sdk.captcha.dto.TencentCaptchaDTO;
import com.tencentcloudapi.captcha.v20190722.models.DescribeCaptchaResultRequest;
/**
* @author sr on 2020-08-10
*/
@Mapper
public interface CaptchaRequestMapMapper {
CaptchaRequestMapMapper INSTANCE = Mappers.getMapper(CaptchaRequestMapMapper.class);
/**
* @param dto
* @return
* @author sr on 2020-08-10
*/
@Mappings({
@Mapping(target = "captchaType", constant = "9")
})
DescribeCaptchaResultRequest toRequest(TencentCaptchaDTO dto);
}

View File

@@ -0,0 +1,78 @@
package com.senmesh.sdk.captcha.service;
import org.apache.commons.lang3.StringUtils;
import com.senmesh.common.AlitaResult;
import com.senmesh.common.util.EnvironmentUtils;
import com.senmesh.common.util.RequestUtils;
import com.senmesh.common.util.SpringContextHolder;
import com.senmesh.sdk.captcha.config.CaptchaProperties;
import com.senmesh.sdk.captcha.dto.TencentCaptchaDTO;
import com.senmesh.sdk.captcha.mapstruct.CaptchaRequestMapMapper;
import com.tencentcloudapi.captcha.v20190722.models.DescribeCaptchaResultRequest;
import lombok.extern.slf4j.Slf4j;
/**
* @author sr on 2020-08-10
*/
@Slf4j
public abstract class AbstractTencentCaptchaAppProvider implements ITencentCaptchaAppProvider {
private static final String PARAM_NOT_ENOUTH = "参数缺失";
private ITencentCaptchaService tencentCaptchaService;
private String appIdKey;
private String appSecretKey;
private CaptchaProperties captchaProperties;
protected AbstractTencentCaptchaAppProvider(ITencentCaptchaService tencentCaptchaService,
CaptchaProperties captchaProperties) {
this.tencentCaptchaService = tencentCaptchaService;
this.captchaProperties = captchaProperties;
}
private String getAppIdKey() {
if (appIdKey == null) {
appIdKey = captchaProperties.getTencent().getApp().get(getAppType()).getAppId();
}
return appIdKey;
}
private String getAppSecretKey() {
if (appSecretKey == null) {
appSecretKey = captchaProperties.getTencent().getApp().get(getAppType()).getAppSecret();
}
return appSecretKey;
}
@Override
public AlitaResult<Boolean> verify(TencentCaptchaDTO tencentCaptchaDTO) {
try {
if (StringUtils.isBlank(tencentCaptchaDTO.getTicket()) || StringUtils.isBlank(tencentCaptchaDTO.getRandstr())) {
return AlitaResult.bizError(PARAM_NOT_ENOUTH);
}
DescribeCaptchaResultRequest request =
CaptchaRequestMapMapper.INSTANCE.toRequest(tencentCaptchaDTO);
// 用户ip
if (StringUtils.isBlank(request.getUserIp())) {
request.setUserIp(RequestUtils.getIpAddress(SpringContextHolder.getRequest()));
}
// 应用id secret
if (request.getCaptchaAppId() == null) {
request.setCaptchaAppId(Long.valueOf(EnvironmentUtils.getProperty(getAppIdKey())));
request.setAppSecretKey(EnvironmentUtils.getProperty(getAppSecretKey()));
}
return tencentCaptchaService.verify(request);
} catch (Exception e) {
log.error("tencent captcha verify error", e);
return AlitaResult.bizError("验证失败:{}" + e.getMessage());
}
}
public AlitaResult<Boolean> verify(String ticket, String randstr) {
TencentCaptchaDTO tencentCaptchaDTO = new TencentCaptchaDTO(ticket, randstr);
return this.verify(tencentCaptchaDTO);
}
}

View File

@@ -0,0 +1,23 @@
package com.senmesh.sdk.captcha.service;
import com.senmesh.common.AlitaResult;
import com.senmesh.sdk.captcha.dto.TencentCaptchaDTO;
/**
* @author sr on 2020-08-10
*/
public interface ITencentCaptchaAppProvider {
/**
* 验证应用类型;
* 同时确定应用id属性配置键
* id键:captcha.tencent.${appType}.appId,secret键:id键:captcha.tencent.${appType}.appSecret
*
* @return
* @author sr on 2020-08-10
*/
String getAppType();
AlitaResult<Boolean> verify(TencentCaptchaDTO tencentCaptchaDTO);
}

View File

@@ -0,0 +1,20 @@
package com.senmesh.sdk.captcha.service;
import com.senmesh.common.AlitaResult;
import com.tencentcloudapi.captcha.v20190722.models.DescribeCaptchaResultRequest;
/**
* @author sr on 2020-08-10
*/
public interface ITencentCaptchaService {
/**
* 验证
*
* @param request
* @return
* @author sr on 2020-08-10
*/
AlitaResult<Boolean> verify(DescribeCaptchaResultRequest request);
}

View File

@@ -0,0 +1,23 @@
package com.senmesh.sdk.captcha.service.impl;
import com.senmesh.sdk.captcha.config.CaptchaProperties;
import com.senmesh.sdk.captcha.service.AbstractTencentCaptchaAppProvider;
import com.senmesh.sdk.captcha.service.ITencentCaptchaService;
/**
* 登录防水墙
*
* @author sr on 2020-08-11
*/
public class LoginCaptchaAppProvider extends AbstractTencentCaptchaAppProvider {
public LoginCaptchaAppProvider(ITencentCaptchaService tencentCaptchaService, CaptchaProperties captchaProperties) {
super(tencentCaptchaService, captchaProperties);
}
@Override
public String getAppType() {
return "login";
}
}

View File

@@ -0,0 +1,55 @@
package com.senmesh.sdk.captcha.service.impl;
import org.apache.commons.lang3.StringUtils;
import com.senmesh.common.AlitaResult;
import com.senmesh.sdk.captcha.service.ITencentCaptchaService;
import com.tencentcloudapi.captcha.v20190722.CaptchaClient;
import com.tencentcloudapi.captcha.v20190722.models.DescribeCaptchaResultRequest;
import com.tencentcloudapi.captcha.v20190722.models.DescribeCaptchaResultResponse;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import lombok.extern.slf4j.Slf4j;
/**
* @author sr on 2020-08-10
*/
@Slf4j
public class TencentCaptchaServiceImpl implements ITencentCaptchaService {
private static final Long SUCCESS_CODE = 1L;
private Credential defaultCredential;
public TencentCaptchaServiceImpl(Credential defaultCredential) {
this.defaultCredential = defaultCredential;
}
@Override
public AlitaResult<Boolean> verify(DescribeCaptchaResultRequest request) {
try {
Credential cred = defaultCredential;
HttpProfile httpProfile = new HttpProfile();
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
CaptchaClient client = new CaptchaClient(cred, "", clientProfile);
log.info("tencent captcha request:{}", request);
DescribeCaptchaResultResponse resp = client.DescribeCaptchaResult(request);
log.info("tencent captcha response:{}", resp);
Long captchaCode = resp.getCaptchaCode();
if (SUCCESS_CODE.equals(captchaCode)) {
return AlitaResult.success(true);
}
String msg = resp.getCaptchaMsg();
return AlitaResult.success(StringUtils.isBlank(msg) ? captchaCode.toString() : msg, false);
} catch (TencentCloudSDKException e) {
log.info("tencent captcha error", e);
return AlitaResult.bizError(e.getMessage());
}
}
}

View File

@@ -0,0 +1,21 @@
package com.senmesh.sdk.chuanglan.config;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 接口链接地址映射
* @author fzp on 2021年6月17日09:29:06
*/
@Data
@NoArgsConstructor
public class ChuangLanCommonProperties {
/** 是否启用 **/
private Boolean enable = Boolean.FALSE;
/** 接口地址 **/
private String url;
/** 次数限制 **/
private Long numLimit;
}

View File

@@ -0,0 +1,59 @@
package com.senmesh.sdk.chuanglan.config;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 创蓝配置
*
* @author sr on 2020-04-09
*/
@ConfigurationProperties(prefix = ChuangLanProperties.PREFIX)
@Data
@Component
@NoArgsConstructor
public class ChuangLanProperties {
/** 创蓝配置前缀 */
public static final String PREFIX = "chuanglan";
/** 创蓝三要素配置前缀 */
public static final String PHONE_THREE_PREFIX = PREFIX + ".phone3";
/** 创蓝三要素配置前缀 */
public static final String BANK_CARD_THREE_PREFIX = PREFIX + ".bankCard3";
/** 创蓝四要素配置前缀 */
public static final String BANK_CARD_FOUR_PREFIX = PREFIX + ".bankCard4";
/** 创蓝二要素实名认证配置前缀 */
public static final String REAL_NAME_TWO_PREFIX = PREFIX + ".realName2";
/** 创蓝二要素实名认证配置前缀 */
public static final String REAL_NAME_TWO_BASE_PREFIX = PREFIX + ".realName2Base";
/** 是否启用 **/
private Boolean enable;
/** https://api.253.com */
private String domain;
/** 系统预留手机号 */
private String phone;
private String appId;
private String appSecret;
/** 手机号三要素配置 */
private ChuangLanCommonProperties phone3;
/** 银行卡三要素配置 */
private ChuangLanCommonProperties bankCard3;
/** 银行卡四要素配置 */
private ChuangLanCommonProperties bankCard4;
/** 实名认证二要素配置 */
private ChuangLanCommonProperties realName2;
/** 实名认证二要素配置 (id-card-auth) */
private ChuangLanCommonProperties realName2Base;
}

View File

@@ -0,0 +1,83 @@
package com.senmesh.sdk.chuanglan.constant;
import com.google.common.collect.Maps;
import com.senmesh.common.AlitaResult;
import com.senmesh.common.util.JsonUtils;
import com.senmesh.sdk.chuanglan.dto.ChuangLanResponseDTO;
import com.senmesh.sdk.chuanglan.dto.ChuangLanResultDTO;
import java.util.Map;
/**
* @author czy
* @date 2021-07-05
*/
public enum BankCardVerifyStateEnum {
/** 认证一致 **/
SUC("01", "认证一致", Boolean.TRUE),
/** 认证不一致 **/
FAIL("02", "认证不一致", Boolean.FALSE),
/** 认证不确定 **/
UNCERTAIN("03", "认证不确定", null),
/** 认证失败 **/
EXCEPTION_FAIL("04", "认证失败", null),
/** 手机号码不匹配 **/
MOBILE_ERROR("05", "手机号码不匹配", Boolean.FALSE),
/** 身份证号码不匹配 **/
CARD_NO_ERROR("06", "身份证号码不匹配", Boolean.FALSE),
/** 姓名不匹配 **/
NAME_ERROR("07", "姓名不匹配", Boolean.FALSE);
private static Map<String, BankCardVerifyStateEnum> stateMap;
/** 验证结果 **/
private String state;
/** 说明 **/
private String msg;
/** 认证结果 **/
private Boolean result;
BankCardVerifyStateEnum(String state, String msg, Boolean result) {
this.state = state;
this.msg = msg;
this.result = result;
}
static {
BankCardVerifyStateEnum[] array = BankCardVerifyStateEnum.values();
stateMap = Maps.newHashMapWithExpectedSize(array.length);
for (BankCardVerifyStateEnum stateEnum : array) {
stateMap.put(stateEnum.getState(), stateEnum);
}
}
public String getState() {
return state;
}
public String getMsg() {
return msg;
}
public Boolean getResult() {
return result;
}
public static AlitaResult<ChuangLanResultDTO> dealState(ChuangLanResponseDTO responseDto) {
ChuangLanResultDTO resultDTO = ChuangLanResultDTO.builder()
.jsonData(JsonUtils.toJsonString(responseDto)).build();
String status = responseDto.getData().getResult();
BankCardVerifyStateEnum stateEnum = stateMap.get(status);
if (stateEnum == null) {
return AlitaResult.success("state not available...", resultDTO);
}
if (stateEnum == SUC || stateEnum == FAIL || stateEnum == MOBILE_ERROR || stateEnum == CARD_NO_ERROR || stateEnum == NAME_ERROR) {
resultDTO.setStatus(stateEnum.getResult());
return AlitaResult.success(stateEnum.getMsg(), resultDTO);
}
return AlitaResult.error(stateEnum.getMsg(), resultDTO);
}
}

View File

@@ -0,0 +1,22 @@
package com.senmesh.sdk.chuanglan.constant;
import com.senmesh.sdk.common.constant.SdkConstants;
/**
* @author sr on 2020-04-10
*/
public interface ChuangLanConstants {
/** 创蓝接口调用,验证成功码 **/
String IMPL_CODE = "01";
/** 成功码 **/
String SUC_CODE = "200000";
/** ================ chuanglan 调起真实服务前异常msg ================= **/
String PROPERTIES_NOT_SET = SdkConstants.CL_CODE + ":配置文件未配置";
String ID_SECRET_NOT_ENOUGH = SdkConstants.CL_CODE + ":参数appId或appSecret缺失";
/** ================ chuanglanW 调起真实服务前异常msq ================= **/
}

View File

@@ -0,0 +1,33 @@
package com.senmesh.sdk.chuanglan.constant;
/**
* sdk创蓝错误码枚举;标识:创蓝(01)
* @author sr on 2020-05-22
*/
public enum ChuangLanErrorCodeEnum {
/** 创蓝调用返回错误码 **/
INVOKE_RETURN_ERROR("060101", "创蓝接口调用失败,返回错误码"),
/** 创蓝调用成功,但信息不匹配 **/
NOT_EQUAL("060102", "不匹配");
/** 错误码 **/
private String code;
/** 错误信息 **/
private String msg;
ChuangLanErrorCodeEnum(String code, String msg){
this.code = code;
this.msg = msg;
}
public String getCode() {
return code;
}
public String getMsg() {
return msg;
}
}

View File

@@ -0,0 +1,35 @@
package com.senmesh.sdk.chuanglan.dto;
import lombok.*;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* 银行卡四要素请求
*
* @author fzp 2021年6月15日15:11:31
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class BankCardFourRequestDTO extends ChuangLanRequestDTO implements Serializable {
/** **/
private static final long serialVersionUID = 3807618123977056991L;
/** 姓名 **/
@NotBlank(message = "姓名不能为空")
private String name;
/** 身份证号 **/
@NotBlank(message = "身份证号不能为空")
private String idNum;
/** 银行卡号 **/
@NotBlank(message = "银行卡号不能为空")
private String cardNo;
@NotBlank(message = "手机号码不能为空")
private String mobile;
}

View File

@@ -0,0 +1,33 @@
package com.senmesh.sdk.chuanglan.dto;
import lombok.*;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* 银行卡三要素请求
*
* @author sr on 2020-04-09
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class BankCardThreeRequestDTO extends ChuangLanRequestDTO implements Serializable {
/** **/
private static final long serialVersionUID = -6539738426193243916L;
/** 姓名 **/
@NotBlank(message = "姓名不能为空")
private String name;
/** 身份证号 **/
@NotBlank(message = "身份证号不能为空")
private String idNum;
/** 银行卡号 **/
@NotBlank(message = "银行卡号不能为空")
private String cardNo;
}

View File

@@ -0,0 +1,27 @@
package com.senmesh.sdk.chuanglan.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 创蓝请求父类dto
*
* @author fzp on 2021年6月15日16:39:50
*/
@Data
@NoArgsConstructor
public class ChuangLanRequestDTO implements Serializable {
private static final long serialVersionUID = 3960499271644654446L;
/**
* id
**/
private String appId;
/**
* secret
**/
private String appKey;
}

View File

@@ -0,0 +1,81 @@
package com.senmesh.sdk.chuanglan.dto;
import com.senmesh.common.AlitaResult;
import com.senmesh.sdk.fangxinqian.constant.FxqConstants;
import com.senmesh.sdk.fangxinqian.constant.FxqErrorCodeEnum;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.util.StringUtils;
import java.io.Serializable;
/**
* 创蓝返回
*
* @param <T>
* @author fzp on 2021年6月15日14:55:38
*/
@Data
@NoArgsConstructor
public class ChuangLanResponseDTO<T> implements Serializable {
/**
*
**/
private static final long serialVersionUID = -4576000729533850612L;
/**
* 错误码
**/
private String code;
/**
* 序列号(每次调用接口返回的唯一值,seqNo 如有接口问题,请提供此值)
**/
private String seqNo;
/**
* 错误信息 1
**/
private String message;
/**
* 错误信息 2
*/
private String msg;
/**
* 响应结果
*/
private StatusDataDTO data;
public static ChuangLanResponseDTO buildCommonError() {
ChuangLanResponseDTO clResponseDTO = new ChuangLanResponseDTO();
clResponseDTO.setCode("999");
return clResponseDTO;
}
/**
* 返回结果处理
*
* @return
*/
public AlitaResult<T> handleResult() {
if (FxqConstants.SUC_CODE.equals(this.getCode())) {
return AlitaResult.success(handleData());
} else {
return AlitaResult.error(FxqErrorCodeEnum.INVOKE_RETURN_ERROR.getCode(),
StringUtils.isEmpty(this.getMsg()) ?
StringUtils.isEmpty(this.getMessage()) ? FxqErrorCodeEnum.INVOKE_RETURN_ERROR.getMsg() : this.getMessage()
: this.getMsg());
}
}
/**
* 子类DTO实现 转换为AlitaResult时
* 通过 handleData()决定转换为AlitaResult的data返回什么
*
* @return
*/
protected T handleData() {
return null;
}
}

View File

@@ -0,0 +1,23 @@
package com.senmesh.sdk.chuanglan.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author czy
* @date 2021-07-05
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ChuangLanResultDTO {
private Boolean status;
private String jsonData;
}

View File

@@ -0,0 +1,36 @@
package com.senmesh.sdk.chuanglan.dto;
import java.io.Serializable;
import javax.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* 手机号三要素请求
*
* @author sr on 2020-04-09
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class PhoneThreeRequestDTO extends ChuangLanRequestDTO implements Serializable {
/** **/
private static final long serialVersionUID = -6539738426193243916L;
/** 姓名 **/
@NotBlank(message = "姓名不能为空")
private String name;
/** 身份证号 **/
@NotBlank(message = "身份证号不能为空")
private String idNum;
/** 银行卡号 **/
@NotBlank(message = "手机号不能为空")
private String mobile;
}

View File

@@ -0,0 +1,28 @@
package com.senmesh.sdk.chuanglan.dto;
import lombok.*;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* 实名认证(基础)
*
* @author fzp 2021年6月15日15:11:31
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class RealNameTwoBaseRequestDTO extends ChuangLanRequestDTO implements Serializable {
private static final long serialVersionUID = -3985001434329229012L;
/** 姓名 **/
@NotBlank(message = "姓名不能为空")
private String name;
/** 身份证号 **/
@NotBlank(message = "身份证号不能为空")
private String idNum;
}

View File

@@ -0,0 +1,38 @@
package com.senmesh.sdk.chuanglan.dto;
import lombok.*;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* 实名认证
*
* @author fzp 2021年6月15日15:11:31
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class RealNameTwoRequestDTO extends ChuangLanRequestDTO implements Serializable {
/** **/
private static final long serialVersionUID = 3807618123977056991L;
/** 姓名 **/
@NotBlank(message = "姓名不能为空")
private String name;
/** 身份证号 **/
@NotBlank(message = "身份证号不能为空")
private String idNum;
/** 身份证有效开始日期 **/
@NotBlank(message = "startTime")
private String startTime;
/** 身份证有效结束日期 **/
@NotBlank(message = "startTime")
private String endTime;
}

View File

@@ -0,0 +1,41 @@
package com.senmesh.sdk.chuanglan.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author czy
* @date 2021-07-05
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class StatusDataDTO {
@ApiModelProperty("业务唯一流水号")
private String orderNo;
@ApiModelProperty("查询时间")
private String handleTime;
@ApiModelProperty("认证结果代码")
private String result;
@ApiModelProperty("备注")
private String remark;
@ApiModelProperty("银行卡所属银行")
private String bankName;
@ApiModelProperty("银行卡类型")
private String cardType;
@ApiModelProperty("银行卡类型")
private String cardCategory;
}

View File

@@ -0,0 +1,71 @@
package com.senmesh.sdk.chuanglan.service;
import com.senmesh.common.AlitaResult;
import com.senmesh.sdk.chuanglan.dto.*;
import org.springframework.validation.annotation.Validated;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.validation.groups.Default;
/**
* 创蓝
*
* @author sr on 2020-04-09
*/
@Validated(Default.class)
public interface ChuangLanService {
String BEAN_ID = "sdk.chuangLanService";
String MOCK_BEAN_ID = "mock.chuangLanService";
/**
* 二要素(基础)
*
* @param requestDTO 请求dto
* @return {@link AlitaResult}<{@link ChuangLanResultDTO}>
*/
AlitaResult<ChuangLanResultDTO> checkRealNameTwoBase(RealNameTwoBaseRequestDTO requestDTO);
/**
* 手机三要素
*
* @param phoneThreeRequestDTO 电话请求dto
* @return {@link AlitaResult}<{@link ChuangLanResultDTO}>
*/
AlitaResult<ChuangLanResultDTO> checkPhoneThree(
@NotNull @Valid PhoneThreeRequestDTO phoneThreeRequestDTO);
/**
* 银行卡三要素
*
* @param bankCardThreeRequestDto
* @return success-false真实调用第三方未成功,未拿到返回值;
* success-true获取到第三方返回,data-true校验成功,data-false校验不一致并返回失败原因(msg)
* @author sr on 2020-04-10
*/
AlitaResult<ChuangLanResultDTO> checkBankCardThree(
@NotNull @Valid BankCardThreeRequestDTO bankCardThreeRequestDto);
/**
* 银行卡四要素
*
* @param bankCardFourRequestDto
* @return success-false真实调用第三方未成功,未拿到返回值;
* success-true获取到第三方返回,data-true校验成功,data-false校验不一致并返回失败原因(msg)
* @author sr on 2020-05-22
*/
AlitaResult<ChuangLanResultDTO> checkBankCardFour(
@NotNull @Valid BankCardFourRequestDTO bankCardFourRequestDto);
/**
* 二要素--实名认证
*
* @param realNameTwoRequestDTO
* @return success-false真实调用第三方未成功,未拿到返回值;
* success-true获取到第三方返回,data-true校验成功,data-false校验不一致并返回失败原因(msg)
* @author sr on 2020-05-22
*/
AlitaResult<ChuangLanResultDTO> realNameTwoAuthentication(
@NotNull @Valid RealNameTwoRequestDTO realNameTwoRequestDTO);
}

View File

@@ -0,0 +1,97 @@
package com.senmesh.sdk.chuanglan.service.impl;
import com.senmesh.common.AlitaResult;
import com.senmesh.common.annotation.CheckAndMock;
import com.senmesh.sdk.chuanglan.config.ChuangLanCommonProperties;
import com.senmesh.sdk.chuanglan.config.ChuangLanProperties;
import com.senmesh.sdk.chuanglan.constant.BankCardVerifyStateEnum;
import com.senmesh.sdk.chuanglan.constant.ChuangLanConstants;
import com.senmesh.sdk.chuanglan.dto.*;
import com.senmesh.sdk.chuanglan.service.ChuangLanService;
import com.senmesh.sdk.chuanglan.util.ChuangLanUtils;
import com.senmesh.sdk.chuanglan.util.HttpUtilCl;
import com.senmesh.sdk.common.constant.SdkConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author fzp on 2021年6月15日16:46:26
*/
@Slf4j
@Service(ChuangLanService.BEAN_ID)
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ChuangLanServiceImpl implements ChuangLanService {
private final ChuangLanProperties chuangLanProperties;
@Override
@CheckAndMock(mockClass = MockChuangLanServiceImpl.class,
propertyPrefix = ChuangLanProperties.REAL_NAME_TWO_BASE_PREFIX)
public AlitaResult<ChuangLanResultDTO> checkRealNameTwoBase(RealNameTwoBaseRequestDTO requestDTO) {
return this.check(requestDTO, chuangLanProperties.getRealName2Base());
}
@Override
@CheckAndMock(mockClass = MockChuangLanServiceImpl.class,
propertyPrefix = ChuangLanProperties.PHONE_THREE_PREFIX)
public AlitaResult<ChuangLanResultDTO> checkPhoneThree(PhoneThreeRequestDTO requestDTO) {
return this.check(requestDTO, chuangLanProperties.getPhone3());
}
@Override
@CheckAndMock(mockClass = MockChuangLanServiceImpl.class,
propertyPrefix = ChuangLanProperties.BANK_CARD_THREE_PREFIX)
public AlitaResult<ChuangLanResultDTO> checkBankCardThree(BankCardThreeRequestDTO bankCardThreeRequestDto) {
return this.check(bankCardThreeRequestDto, chuangLanProperties.getBankCard3());
}
@Override
@CheckAndMock(mockClass = MockChuangLanServiceImpl.class,
propertyPrefix = ChuangLanProperties.BANK_CARD_FOUR_PREFIX)
public AlitaResult<ChuangLanResultDTO> checkBankCardFour(BankCardFourRequestDTO bankCardFourRequestDto) {
return this.check(bankCardFourRequestDto, chuangLanProperties.getBankCard4());
}
@Override
@CheckAndMock(mockClass = MockChuangLanServiceImpl.class,
propertyPrefix = ChuangLanProperties.REAL_NAME_TWO_PREFIX)
public AlitaResult<ChuangLanResultDTO> realNameTwoAuthentication(RealNameTwoRequestDTO realNameTwoRequestDTO){
return this.check(realNameTwoRequestDTO, chuangLanProperties.getRealName2());
}
/**
* 父类dto 添加请求父类,可以指定appId,appSecret调用接口
* @param requestDto
* @param commonProperties
* @return
*/
private AlitaResult<ChuangLanResultDTO> check(ChuangLanRequestDTO requestDto, ChuangLanCommonProperties commonProperties) {
// 校验部分
if (commonProperties == null || chuangLanProperties == null) {
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE,
ChuangLanConstants.PROPERTIES_NOT_SET);
}
if (!Boolean.TRUE.equals(chuangLanProperties.getEnable())) {
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE,
"暂不支持要素认证");
}
if (!ChuangLanUtils.dealAppIdAndSecret(commonProperties, requestDto, chuangLanProperties)) {
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE,
ChuangLanConstants.ID_SECRET_NOT_ENOUGH);
}
// 执行
ChuangLanResponseDTO responseDto = HttpUtilCl.execute(chuangLanProperties.getDomain().concat(commonProperties.getUrl()), requestDto);
// 返回结果校验
if (!ChuangLanConstants.SUC_CODE.equals(responseDto.getCode())) {
// 返回结果验证错误
return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_RESPONSE_FAIL_CODE, responseDto.getMessage() );
}
return BankCardVerifyStateEnum.dealState(responseDto);
}
}

View File

@@ -0,0 +1,75 @@
package com.senmesh.sdk.chuanglan.service.impl;
import com.senmesh.common.AlitaResult;
import com.senmesh.sdk.chuanglan.config.ChuangLanProperties;
import com.senmesh.sdk.chuanglan.dto.*;
import com.senmesh.sdk.chuanglan.service.ChuangLanService;
import com.senmesh.sdk.common.constant.SdkConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
/**
* @author sr on 2020-04-09
*/
@Service(ChuangLanService.MOCK_BEAN_ID)
@Slf4j
public class MockChuangLanServiceImpl implements ChuangLanService {
private final static ChuangLanResultDTO result =
ChuangLanResultDTO.builder().status(Boolean.TRUE).build();
@Autowired
private ChuangLanProperties chuangLanProperties;
private AlitaResult<ChuangLanResultDTO> check() {
// 校验部分
if (chuangLanProperties == null || !Boolean.TRUE.equals(chuangLanProperties.getEnable())) {
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE,
"暂不支持要素认证");
}
return AlitaResult.success(result);
}
@Override
public AlitaResult<ChuangLanResultDTO> checkRealNameTwoBase(
RealNameTwoBaseRequestDTO requestDTO) {
log.info("chuanglan checkRealNameTwoBase mock...");
return check();
}
@Override
public AlitaResult<ChuangLanResultDTO> checkPhoneThree(
PhoneThreeRequestDTO phoneThreeRequestDTO) {
log.info("chuanglan checkPhoneThree mock...");
return check();
}
@Override
public AlitaResult<ChuangLanResultDTO> checkBankCardThree(
@NotNull @Valid BankCardThreeRequestDTO bankCardThreeRequestDto) {
log.info("chuanglan checkBankCardThree mock...");
return check();
}
@Override
public AlitaResult<ChuangLanResultDTO> checkBankCardFour(
@NotNull @Valid BankCardFourRequestDTO bankCardFourRequestDto) {
log.info("chuanglan checkBankCardFour mock...");
return check();
}
@Override
public AlitaResult<ChuangLanResultDTO> realNameTwoAuthentication(
RealNameTwoRequestDTO realNameTwoRequestDTO) {
log.info("chuanglan checkRealNameTwo mock...");
return check();
}
}

View File

@@ -0,0 +1,52 @@
package com.senmesh.sdk.chuanglan.util;
import com.senmesh.sdk.chuanglan.config.ChuangLanCommonProperties;
import com.senmesh.sdk.chuanglan.config.ChuangLanProperties;
import com.senmesh.sdk.chuanglan.dto.ChuangLanRequestDTO;
import org.apache.commons.lang3.StringUtils;
/**
* 工具类
*
* @author fzp on 2021年6月15日14:22:18
*/
public final class ChuangLanUtils {
/**
* 私有
*/
private ChuangLanUtils() {
throw new IllegalStateException("Utility class");
}
/**
* 处理appId和appSecret参数
*
* @param <T>
* @param commonProperties
* @param requestDto
* @author fzp on 2021年6月15日16:20:49
*/
public static <T extends ChuangLanRequestDTO> boolean dealAppIdAndSecret(ChuangLanCommonProperties commonProperties,
T requestDto, ChuangLanProperties chuangLanProperties) {
String appId = requestDto.getAppId();
String appKey = requestDto.getAppKey();
// 如果appId为空,则从nacos配置文件读取
if (StringUtils.isBlank(appId) && commonProperties.getEnable()) {
appId = chuangLanProperties.getAppId();
}
if (StringUtils.isBlank(appKey) && commonProperties.getEnable()) {
appKey = chuangLanProperties.getAppSecret();
}
if (StringUtils.isBlank(appId) || StringUtils.isBlank(appKey)) {
return false;
}
requestDto.setAppId(appId);
requestDto.setAppKey(appKey);
return true;
}
}

View File

@@ -0,0 +1,98 @@
package com.senmesh.sdk.chuanglan.util;
import com.senmesh.common.util.JsonUtils;
import com.senmesh.sdk.chuanglan.constant.ChuangLanConstants;
import com.senmesh.sdk.chuanglan.dto.ChuangLanResponseDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StopWatch;
import org.springframework.web.client.RestTemplate;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
@Slf4j
@Component
public class HttpUtilCl<T, R> {
private static RestTemplate restTemplate;
@Autowired
public HttpUtilCl() {
this.restTemplate = new RestTemplate();
}
/**
* Http 通用请求封装
*
* @param url 请求地址
* @param requestDto 请求实体
* @param <T>
* @param <R>
* @return
*/
public static <T, R extends ChuangLanResponseDTO> ChuangLanResponseDTO execute(String url, T requestDto) {
ChuangLanResponseDTO result;
StopWatch stopWatch = new StopWatch();
stopWatch.start();
try {
String reqJson = JsonUtils.toJsonString(requestDto);
log.info("chuanglan request url :{}", url);
log.info("chuanglan request requestDto :{}", reqJson);
MultiValueMap requestBody = new LinkedMultiValueMap();
Map paramMap = JsonUtils.toMap(reqJson);
paramMap.forEach((k,v) -> {
if(Objects.nonNull(v)){
requestBody.add(k,v);
}
});
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity request = new HttpEntity(requestBody, headers);
String response = restTemplate.postForObject(url, request, String.class);
log.info("chuanglan 响应结果 :{}", response);
result = formatDto(response);
} catch (Exception e) {
log.error("chuanglan {} invoke error:{}", requestDto.getClass().getName(), e);
stopWatch.stop();
return ChuangLanResponseDTO.buildCommonError();
}
stopWatch.stop();
log.info("chuanglan consuming {} s", stopWatch.getTotalTimeSeconds());
return result;
}
private static ChuangLanResponseDTO formatDto(String json){
if(StringUtils.isBlank(json)){
return ChuangLanResponseDTO.buildCommonError();
}
ChuangLanResponseDTO result = JsonUtils.toObject(json,ChuangLanResponseDTO.class);
Map<String,Object> map = JsonUtils.toMap(json);
if(map.get("data") != null){
LinkedHashMap data = (LinkedHashMap) map.get("data");
// 创蓝接口验证失败
if(!ChuangLanConstants.IMPL_CODE.equals(data.get("result"))){
result.setMsg(data.get("remark") + "");
result.setMessage(data.get("remark") + "");
// result.setCode(data.get("result") + "");
}
}
return result;
}
}

View File

@@ -0,0 +1,73 @@
package com.senmesh.sdk.common.config;
import java.util.List;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import com.google.common.collect.Lists;
/**
* @author sr on 2020-04-16
*/
@Configuration
public class ApiConfig {
/**
* 读取超时
**/
public static final int READ_TIME_OUT = 60000;
/**
* 连接超时
**/
public static final int CONNECT_TIME_OUT = 60000;
@Bean
@ConditionalOnMissingBean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
List<MediaType> mediaTypes = Lists.newArrayList(MediaType.APPLICATION_ATOM_XML,
MediaType.APPLICATION_FORM_URLENCODED,
MediaType.APPLICATION_JSON,
MediaType.APPLICATION_JSON_UTF8,
MediaType.APPLICATION_OCTET_STREAM,
MediaType.APPLICATION_PDF,
MediaType.APPLICATION_PROBLEM_JSON,
MediaType.APPLICATION_PROBLEM_JSON_UTF8,
MediaType.APPLICATION_PROBLEM_XML,
MediaType.APPLICATION_RSS_XML,
MediaType.APPLICATION_STREAM_JSON,
MediaType.APPLICATION_XHTML_XML,
MediaType.APPLICATION_XML,
MediaType.IMAGE_GIF,
MediaType.IMAGE_JPEG,
MediaType.IMAGE_PNG,
MediaType.MULTIPART_FORM_DATA,
MediaType.TEXT_EVENT_STREAM,
MediaType.TEXT_HTML,
MediaType.TEXT_MARKDOWN,
MediaType.TEXT_PLAIN,
MediaType.TEXT_XML);
converter.setSupportedMediaTypes(mediaTypes);
restTemplate.getMessageConverters().add(converter);
return restTemplate;
}
@Bean
@ConditionalOnMissingBean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
// 单位为ms
factory.setReadTimeout(READ_TIME_OUT);
factory.setConnectTimeout(CONNECT_TIME_OUT);
return factory;
}
}

View File

@@ -0,0 +1,18 @@
package com.senmesh.sdk.common.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import javax.validation.Validator;
@Configuration
public class ValidConfig {
public MethodValidationPostProcessor methodValidationPostProcessor(Validator validator) {
MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
if (validator != null) {
methodValidationPostProcessor.setValidator(validator);
}
return methodValidationPostProcessor;
}
}

View File

@@ -0,0 +1,39 @@
package com.senmesh.sdk.common.constant;
/**
* @author sr on 2020-04-10
*/
public interface SdkConstants {
String INVOKE_FAIL = "第三方接口调用异常:";
/** ()代表错误码中间两位,如060101是放心签错误码 **/
/** 标识:放心签(01) **/
String FXQ_CODE = "fxq";
/** 标识:短信(02) **/
String SMS_CODE = "sms";
/** 标识:支付宝(03) **/
String ALIPAY_CODE = "alipay";
/** 标识:微信(04) **/
String WECHAT_CODE = "wechat";
/** 标识:创蓝(05) **/
String CL_CODE = "chuanglan";
/** ================ sdk通用异常code ================= **/
/** 调用异常,未调起第三方 **/
String SDK_INVOKE_NOT_REACH_CODE = "060000";
/** 调用异常,http调起第三方异常 **/
String SDK_HTTP_INVOKE_ERROR_CODE = "060001";
/** 调用失败,http调起第三方结果返回,非成功码 **/
String SDK_HTTP_INVOKE_RESPONSE_FAIL_CODE = "060002";
/** 调用失败(业务),http调起第三方结果返回成功,根据业务判断非成功状态 **/
String SDK_HTTP_INVOKE_BUSINESS_FAIL_CODE = "060003";
/** 请求参数异常 **/
String SDK_REQUEST_PARAM_ERROR_CODE = "060004";
/** 结果转换失败 **/
String SDK_RESPONSE_CONVERT_ERROR_CODE = "060005";
/** ================ sdk通用异常code ================= **/
}

View File

@@ -0,0 +1,51 @@
package com.senmesh.sdk.common.dto;
import java.io.Serializable;
import java.util.Date;
import com.senmesh.common.util.RandomUtils;
import lombok.AllArgsConstructor;
import lombok.Builder.Default;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
/**
* sdk 调用日志对象
*
* @author sr on 2021-01-27
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
public class AbstractSdkInvokeLogDTO implements Serializable {
/** **/
private static final long serialVersionUID = 4230907893212819576L;
/** 请求对象 **/
private Object requestData;
/** 结果对象 **/
private Object responseData;
/** 请求时间 **/
@Default
private Date requestDate = new Date();
/** 请求标识 **/
@Default
private String requestId = RandomUtils.generateUUID();
/** 具体方法类型 **/
private String methodType;
/** 调用耗时(单位毫秒) **/
private Long useTime;
public String getMethodType() {
if (methodType == null && requestData != null) {
methodType = requestData instanceof ISdkRequest ? ((ISdkRequest) requestData).getMethodName()
: requestData.getClass().getSimpleName();
}
return methodType;
}
}

View File

@@ -0,0 +1,29 @@
package com.senmesh.sdk.common.dto;
import org.springframework.data.annotation.Transient;
import lombok.AllArgsConstructor;
import lombok.Builder.Default;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
/**
* 默认sdk调用日志对象
* @author sr on 2021-03-18
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
public class DefaultSdkInvokeLogDTO extends AbstractSdkInvokeLogDTO{
/** **/
private static final long serialVersionUID = -7870863791739331150L;
/** 分类集合名称(mongo使用) **/
@Transient
@Default
private String collectionName = "default_sdk_invoke_log";
}

View File

@@ -0,0 +1,55 @@
package com.senmesh.sdk.common.dto;
import java.io.Serializable;
import org.springframework.core.ParameterizedTypeReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
/**
* 请求对象
* @author sr on 2021-03-18
*/
public interface ISdkRequest<RES> extends Serializable{
/**
* 方法名
* @return
* @author sr on 2021-12-27
*/
@JsonIgnore
default String getMethodName() {
return this.getClass().getSimpleName();
}
/**
* 调用uri
* @return
* @author sr on 2021-12-27
*/
@JsonIgnore
default String getUri() {
return null;
}
/**
* 结果集普通类型
* @return
* @author sr on 2021-12-20
*/
@JsonIgnore
default Class<RES> getResponseClass() {
return null;
}
/**
* 结果集带范性类型
* @return
* @author sr on 2021-12-20
*/
@JsonIgnore
default ParameterizedTypeReference<RES> getResponseType() {
return null;
}
}

View File

@@ -0,0 +1,11 @@
package com.senmesh.sdk.common.dto;
import java.io.Serializable;
/**
* 结果
* @author sr on 2021-11-24
*/
public interface ISdkResponse extends Serializable{
}

View File

@@ -0,0 +1,32 @@
package com.senmesh.sdk.common.dto;
import java.io.Serializable;
import com.senmesh.sdk.wechat.model.Watermark;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 小程序用户手机号信息
* @author sr on 2021-11-25
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LiteUserPhoneDTO implements Serializable{
/** **/
private static final long serialVersionUID = 4564606626820175506L;
/** 用户绑定的手机号(国外手机号会有区号) **/
private String phoneNumber;
/** 没有区号的手机号 **/
private String purePhoneNumber;
/** 区号 **/
private String countryCode;
/** 数据水印 **/
private Watermark watermark;
}

View File

@@ -0,0 +1,34 @@
package com.senmesh.sdk.common.exception;
/**
* @author sr on 2020-04-09
*/
public class SdkException extends RuntimeException {
/** **/
private static final long serialVersionUID = 1139970958567895252L;
public SdkException() {
super();
}
public SdkException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public SdkException(String message, Throwable cause) {
super(message, cause);
}
public SdkException(String message) {
super(message);
}
public SdkException(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,97 @@
package com.senmesh.sdk.common.util;
import java.util.List;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.StopWatch;
import org.springframework.web.client.RestTemplate;
import com.google.common.collect.Lists;
import com.senmesh.common.util.JsonUtils;
import com.senmesh.sdk.common.dto.DefaultSdkInvokeLogDTO;
import com.senmesh.sdk.common.dto.ISdkRequest;
import com.senmesh.sdk.common.dto.ISdkResponse;
import com.senmesh.sdk.common.exception.SdkException;
import lombok.extern.slf4j.Slf4j;
/**
* sdk,http调用工具类
* @author sr on 2022-07-26
*/
@Slf4j
public class HttpUtils {
public static RestTemplate restTemplate = new RestTemplate();
static {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
List<MediaType> mediaTypes = Lists.newArrayList(MediaType.APPLICATION_ATOM_XML,
MediaType.APPLICATION_FORM_URLENCODED,
MediaType.APPLICATION_JSON,
MediaType.APPLICATION_JSON_UTF8,
MediaType.APPLICATION_OCTET_STREAM,
MediaType.APPLICATION_PDF,
MediaType.APPLICATION_PROBLEM_JSON,
MediaType.APPLICATION_PROBLEM_JSON_UTF8,
MediaType.APPLICATION_PROBLEM_XML,
MediaType.APPLICATION_RSS_XML,
MediaType.APPLICATION_STREAM_JSON,
MediaType.APPLICATION_XHTML_XML,
MediaType.APPLICATION_XML,
MediaType.IMAGE_GIF,
MediaType.IMAGE_JPEG,
MediaType.IMAGE_PNG,
MediaType.MULTIPART_FORM_DATA,
MediaType.TEXT_EVENT_STREAM,
MediaType.TEXT_HTML,
MediaType.TEXT_MARKDOWN,
MediaType.TEXT_PLAIN,
MediaType.TEXT_XML);
converter.setSupportedMediaTypes(mediaTypes);
restTemplate.getMessageConverters().add(converter);
}
public static <RES extends ISdkResponse> RES post(ISdkRequest<RES> req) throws SdkException {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<?> httpEntity = new HttpEntity<>(req, headers);
return exchange(req, req.getUri(), httpEntity, HttpMethod.POST);
}
public static <RES> RES exchange(ISdkRequest<RES> req, String url, HttpEntity<?> httpEntity,
HttpMethod method) throws SdkException {
Class<RES> responseClass = req.getResponseClass();
ParameterizedTypeReference<?> responseType = req.getResponseType();
Object requestData = httpEntity.getBody();
try {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ResponseEntity<?> response = null;
if (responseClass != null) {
response = restTemplate.exchange(url, method, httpEntity, responseClass);
} else {
response =
restTemplate.exchange(url, method, httpEntity,
responseType);
}
Object body = response.getBody();
stopWatch.stop();
log.info("req:{} invoke:{}, ", req.getClass(), JsonUtils
.toJsonString(DefaultSdkInvokeLogDTO.builder().requestData(requestData).responseData(body)
.useTime(stopWatch.getTotalTimeMillis())
.methodType(req.getMethodName())
.build()));
return (RES) body;
} catch (Exception e) {
log.error("req:{}, :{},{}", req.getClass(), JsonUtils.toJsonString(requestData), e);
throw new SdkException(e);
}
}
}

View File

@@ -0,0 +1,46 @@
package com.senmesh.sdk.common.util;
import java.nio.charset.StandardCharsets;
import java.security.AlgorithmParameters;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import com.senmesh.common.exception.BusinessException;
import com.senmesh.common.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
/**
* 加密器
* @author sr on 2021-11-23
*/
@Slf4j
public class LiteEncryptor {
public static <T> T decrypt(String encryptData, String iv, String sessionKey, Class<T> clazz) {
String decryptStr ;
try {
AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance("AES");
algorithmParameters.init(new IvParameterSpec(Base64.getDecoder().decode(iv)));
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE,
new SecretKeySpec(Base64.getDecoder().decode(sessionKey), "AES"), algorithmParameters);
byte[] decode = PKCS7Encoder.decode(cipher.doFinal(Base64.getDecoder().decode(encryptData)));
decryptStr = new String(decode, StandardCharsets.US_ASCII);
} catch (Exception e) {
log.error("微信解密失败:", e);
throw new BusinessException("微信解密失败");
}
try {
return JsonUtils.toObject(decryptStr, clazz);
} catch (Exception e) {
log.debug(decryptStr);
throw new BusinessException("微信解密失败(可能小程序session_key过期)");
}
}
}

View File

@@ -0,0 +1,67 @@
/**
* 对企业微信发送给企业后台的消息加解密示例代码.
*
* @copyright Copyright (c) 1998-2014 Tencent Inc.
*/
// ------------------------------------------------------------------------
package com.senmesh.sdk.common.util;
import java.nio.charset.Charset;
import java.util.Arrays;
/**
* 提供基于PKCS7算法的加解密接口.
*/
class PKCS7Encoder {
static Charset CHARSET = Charset.forName("utf-8");
static int BLOCK_SIZE = 32;
/**
* 获得对明文进行补位填充的字节.
*
* @param count 需要进行填充补位操作的明文字节个数
* @return 补齐用的字节数组
*/
static byte[] encode(int count) {
// 计算需要填充的位数
int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
if (amountToPad == 0) {
amountToPad = BLOCK_SIZE;
}
// 获得补位所用的字符
char padChr = chr(amountToPad);
String tmp = new String();
for (int index = 0; index < amountToPad; index++) {
tmp += padChr;
}
return tmp.getBytes(CHARSET);
}
/**
* 删除解密后明文的补位字符
*
* @param decrypted 解密后的明文
* @return 删除补位字符后的明文
*/
static byte[] decode(byte[] decrypted) {
int pad = (int) decrypted[decrypted.length - 1];
if (pad < 1 || pad > 32) {
pad = 0;
}
return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
}
/**
* 将数字转化成ASCII码对应的字符,用于对明文进行补码
*
* @param a 需要转化的数字
* @return 转化得到的字符
*/
static char chr(int a) {
byte target = (byte) (a & 0xFF);
return (char) target;
}
}

View File

@@ -0,0 +1,29 @@
package com.senmesh.sdk.deepseek.config;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = DeepSeekProperties.PREFIX)
@Data
@Component
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class DeepSeekProperties implements Serializable{
/** **/
private static final long serialVersionUID = 6362606996602121889L;
public static final String PREFIX = "deepseek";
/** 控制台获取http服务接口认证信息中的APIPassword **/
private String httpAPIPassword;
}

View File

@@ -0,0 +1,65 @@
package com.senmesh.sdk.deepseek.service;
import com.senmesh.common.AlitaResult;
import com.senmesh.common.util.JsonUtils;
import com.senmesh.sdk.common.constant.SdkConstants;
import com.senmesh.sdk.common.dto.DefaultSdkInvokeLogDTO;
import com.senmesh.sdk.common.util.HttpUtils;
import com.senmesh.sdk.deepseek.config.DeepSeekProperties;
import com.senmesh.sdk.xf.model.ChatReq;
import com.senmesh.sdk.xf.model.ChatRes;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class DeepSeekProvider {
private static DeepSeekProperties deepSeekProperties;
private DeepSeekProvider(DeepSeekProperties deepSeekProperties) {
DeepSeekProvider.deepSeekProperties = deepSeekProperties;
}
public static AlitaResult<String> httpChat(ChatReq req) {
return httpChat(req, deepSeekProperties.getHttpAPIPassword());
}
public static AlitaResult<String> httpChat(ChatReq req, String httpAPIPassword) {
ResponseEntity<ChatRes> response = null;
try {
try {
HttpHeaders header = new HttpHeaders();
header.add("Authorization", "Bearer " + httpAPIPassword);
header.add("Content-Type", "application/json");
// 发送请求
HttpEntity requestEntity = new HttpEntity(req, header);
response =
HttpUtils.restTemplate.exchange("https://api.deepseek.com/chat/completions",
HttpMethod.POST, requestEntity, ChatRes.class);
} catch (Exception e) {
log.error("http error:{}", e.getMessage());
return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_ERROR_CODE, e.getMessage());
}
try {
String content = response.getBody().getChoices().get(0).getMessage().getContent();
return AlitaResult.success(content);
} catch (Exception e) {
return AlitaResult.error(SdkConstants.SDK_RESPONSE_CONVERT_ERROR_CODE, "返回结果获取content失败");
}
} finally {
log.info("invoke:{}",
JsonUtils
.toJsonString(
DefaultSdkInvokeLogDTO.builder().requestData(req).responseData(response)
.build()));
}
}
}

View File

@@ -0,0 +1,24 @@
package com.senmesh.sdk.fangxinqian.config;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author sr on 2020-04-09
*/
@Data
@NoArgsConstructor
public class FxqCommonProperties{
/** 是否启用 **/
private Boolean enable = Boolean.FALSE;
/** id **/
private String appId;
/** secret **/
private String appSecret;
/** 接口地址 **/
private String url;
/** 次数限制 **/
private Long numLimit;
}

View File

@@ -0,0 +1,24 @@
package com.senmesh.sdk.fangxinqian.config;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 合同相关配置
*/
@Data
@NoArgsConstructor
public class FxqContractExtensionProperties {
/**
* 是否启用
**/
private Boolean enable = Boolean.FALSE;
/**
* 接口地址
**/
private String url;
/**
* 次数限制
**/
private Long numLimit;
}

View File

@@ -0,0 +1,39 @@
package com.senmesh.sdk.fangxinqian.config;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 合同相关配置
*/
@Data
@NoArgsConstructor
public class FxqContractProperties extends FxqCommonProperties {
/**
* 普通签署
*/
private FxqContractExtensionProperties commonSign;
/**
* 关键字签署
*/
private FxqContractExtensionProperties keySign;
/**
* 存证
*/
private FxqContractExtensionProperties evidenceSave;
/**
* 出证
*/
private FxqContractExtensionProperties evidenceGet;
public FxqCommonProperties build(FxqContractExtensionProperties properties) {
FxqCommonProperties result = new FxqCommonProperties();
result.setAppId(this.getAppId());
result.setAppSecret(this.getAppSecret());
result.setEnable(properties.getEnable());
result.setNumLimit(properties.getNumLimit());
result.setUrl(properties.getUrl());
return result;
}
}

View File

@@ -0,0 +1,112 @@
package com.senmesh.sdk.fangxinqian.config;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 放心签配置
*
* @author sr on 2020-04-09
*/
@ConfigurationProperties(prefix = FxqProperties.PREFIX, ignoreUnknownFields = false)
@Data
@Component
@NoArgsConstructor
public class FxqProperties {
/**
* 放心签配置前缀
**/
public static final String PREFIX = "fangxinqian";
/**
* 放心签三要素配置前缀
**/
public static final String BANK_CARD_THREE_PREFIX = PREFIX + ".bankCard3";
/**
* 放心签四要素配置前缀
**/
public static final String BANK_CARD_FOUR_PREFIX = PREFIX + ".bankCard4";
/**
* 实名认证配置前缀
*/
public static final String REALNAME_AUTH_PREFIX = PREFIX + ".realname";
/**
* 工商核验
*/
public static final String GOVERNMENT_AUTH_PREFIX = PREFIX + ".government";
/**
* 普通签署
*/
public static final String COMMON_SIGN_PREFIX = PREFIX + ".contract.commonSign";
/**
* 关键字签署
*/
public static final String KEY_SIGN_PREFIX = PREFIX + ".contract.keySign";
/**
* 存证
*/
public static final String EVIDENCE_SAVE_PREFIX = PREFIX + ".contract.evidenceSave";
/**
* 出证
*/
public static final String EVIDENCE_GET_PREFIX = PREFIX + ".contract.evidenceGet";
/**
* https://api.fangxinqian.cn
*/
private String domain;
/**
* 系统预留手机号
*/
private String phone;
/**
* 公章uri
*/
private String officialSealUri;
/**
* 个人章uri
*/
private String personalSealUri;
/**
* 合同关键字替换
*/
private String textReplaceUri;
/**
* 银行卡三要素配置
**/
private FxqCommonProperties bankCard3;
/**
* 银行卡四要素配置
**/
private FxqCommonProperties bankCard4;
/**
* 实名认证配置
*/
private FxqCommonProperties realName;
/**
* 工商信息核验配置
*/
private FxqCommonProperties government;
/**
* 合同
*/
private FxqContractProperties contract;
}

View File

@@ -0,0 +1,66 @@
package com.senmesh.sdk.fangxinqian.constant;
import java.util.Map;
import com.google.common.collect.Maps;
import com.senmesh.common.AlitaResult;
/**
* 银行三要素验证结果枚举
*
* @author sr on 2020-04-10
*/
public enum BankCardFourStateEnum {
/** 验证一致 **/
SUC("1", "验证一致"),
/** 验证不一致 **/
FAIL("2", "验证不一致");
private static Map<String, BankCardFourStateEnum> stateMap;
/** 验证结果 **/
private String state;
/** 说明 **/
private String msg;
BankCardFourStateEnum(String state, String msg) {
this.state = state;
this.msg = msg;
}
static {
BankCardFourStateEnum[] array = BankCardFourStateEnum.values();
stateMap = Maps.newHashMapWithExpectedSize(array.length);
for (BankCardFourStateEnum stateEnum : array) {
stateMap.put(stateEnum.getState(), stateEnum);
}
}
public String getState() {
return state;
}
public String getMsg() {
return msg;
}
/**
* 处理验证结果
*
* @param state
* @return
* @author sr on 2020-04-10
*/
public static AlitaResult<Boolean> dealState(String state) {
BankCardFourStateEnum stateEnum = stateMap.get(state);
if (stateEnum == null) {
return AlitaResult.success("state not available...", false);
}
if (stateEnum == SUC) {
return AlitaResult.success(true);
}
return AlitaResult.success(stateEnum.getMsg(), false);
}
}

View File

@@ -0,0 +1,68 @@
package com.senmesh.sdk.fangxinqian.constant;
import java.util.Map;
import com.google.common.collect.Maps;
import com.senmesh.common.AlitaResult;
/**
* 银行三要素验证结果枚举
*
* @author sr on 2020-04-10
*/
public enum BankCardThreeStateEnum {
/** 验证一致 **/
SUC("1", "验证一致"),
/** 验证不一致 **/
FAIL("2", "验证不一致"),
/** 异常情况 **/
UNKNOWN("3", "异常情况");
private static Map<String, BankCardThreeStateEnum> stateMap;
/** 验证结果 **/
private String state;
/** 说明 **/
private String msg;
BankCardThreeStateEnum(String state, String msg) {
this.state = state;
this.msg = msg;
}
static {
BankCardThreeStateEnum[] array = BankCardThreeStateEnum.values();
stateMap = Maps.newHashMapWithExpectedSize(array.length);
for (BankCardThreeStateEnum stateEnum : array) {
stateMap.put(stateEnum.getState(), stateEnum);
}
}
public String getState() {
return state;
}
public String getMsg() {
return msg;
}
/**
* 处理验证结果
*
* @param state
* @return
* @author sr on 2020-04-10
*/
public static AlitaResult<Boolean> dealState(String state) {
BankCardThreeStateEnum stateEnum = stateMap.get(state);
if (stateEnum == null) {
return AlitaResult.success("state not available...", false);
}
if (stateEnum == SUC) {
return AlitaResult.success(true);
}
return AlitaResult.success(stateEnum.getMsg(), false);
}
}

View File

@@ -0,0 +1,19 @@
package com.senmesh.sdk.fangxinqian.constant;
import com.senmesh.sdk.common.constant.SdkConstants;
/**
* @author sr on 2020-04-10
*/
public interface FxqConstants {
/** 成功码 **/
String SUC_CODE = "10000";
/** ================ fxq 调起真实服务前异常msg ================= **/
String PROPERTIES_NOT_SET = SdkConstants.FXQ_CODE + ":配置文件未配置";
String ID_SECRET_NOT_ENOUGH = SdkConstants.FXQ_CODE + ":参数appId或appSecret缺失";
/** ================ fxq 调起真实服务前异常msq ================= **/
}

View File

@@ -0,0 +1,33 @@
package com.senmesh.sdk.fangxinqian.constant;
/**
* sdk放心签错误码枚举;标识:放心签(01)
* @author sr on 2020-05-22
*/
public enum FxqErrorCodeEnum {
/** 放心签调用返回错误码 **/
INVOKE_RETURN_ERROR("060101", "放心签接口调用失败,返回错误码"),
/** 放心签调用成功,但信息不匹配 **/
NOT_EQUAL("060102", "不匹配");
/** 错误码 **/
private String code;
/** 错误信息 **/
private String msg;
FxqErrorCodeEnum(String code, String msg){
this.code = code;
this.msg = msg;
}
public String getCode() {
return code;
}
public String getMsg() {
return msg;
}
}

View File

@@ -0,0 +1,40 @@
package com.senmesh.sdk.fangxinqian.dto;
import java.io.Serializable;
import javax.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* 银行卡四要素请求
*
* @author sr on 2020-04-09
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class BankCardFourRequestDTO extends FxqRequestDTO implements Serializable {
/** **/
private static final long serialVersionUID = 3807618123977056991L;
/** 姓名 **/
@NotBlank(message = "姓名不能为空")
private String name;
/** 身份证号 **/
@NotBlank(message = "身份证号不能为空")
private String identityCode;
/** 银行卡号 **/
@NotBlank(message = "银行卡号不能为空")
private String bankcardNumber;
@NotBlank(message = "手机号码不能为空")
private String phoneNumber;
}

View File

@@ -0,0 +1,29 @@
package com.senmesh.sdk.fangxinqian.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* 银行卡四要素请求
*
* @author sr on 2020-04-09
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString(callSuper = true)
public class BankCardFourResponseDTO extends FxqResponseDTO {
/** **/
private static final long serialVersionUID = 3188936116187424875L;
/** 结果data **/
private StateDataDTO data;
}

View File

@@ -0,0 +1,38 @@
package com.senmesh.sdk.fangxinqian.dto;
import java.io.Serializable;
import javax.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* 银行卡三要素请求
*
* @author sr on 2020-04-09
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class BankCardThreeRequestDTO extends FxqRequestDTO implements Serializable {
/** **/
private static final long serialVersionUID = -6539738426193243916L;
/** 姓名 **/
@NotBlank(message = "姓名不能为空")
private String name;
/** 身份证号 **/
@NotBlank(message = "身份证号不能为空")
private String identityCode;
/** 银行卡号 **/
@NotBlank(message = "银行卡号不能为空")
private String bankcardNumber;
}

View File

@@ -0,0 +1,29 @@
package com.senmesh.sdk.fangxinqian.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* 银行卡三要素请求
*
* @author sr on 2020-04-09
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString(callSuper = true)
public class BankCardThreeResponseDTO extends FxqResponseDTO {
/** **/
private static final long serialVersionUID = 3188936116187424875L;
/** 结果data **/
private StateDataDTO data;
}

View File

@@ -0,0 +1,113 @@
package com.senmesh.sdk.fangxinqian.dto;
import lombok.*;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* 合同签署请求DTO
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ContractRequestDTO extends FxqRequestDTO {
private static final long serialVersionUID = 7354207669664708465L;
/**
* 合同⽂件(base64/云存储⽂件链接)
*/
@NotBlank(message = "合同⽂件不能为空")
private String contract;
/**
* 合同文件名
*/
@NotBlank(message = "合同⽂件名不能为空")
private String title;
/**
* 0.返回签署完成的base64 1.返回云存储⽂件链接 不填默认 0
*/
private String returnType;
/**
* 签署⼈信息
*/
@Valid
@NotNull(message = "签署⼈信息不能为空")
private List<CommonSignSigner> signers;
/**
* 签署人信息
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class CommonSignSigner {
/**
* 真实姓名/公司名称
*/
@NotBlank(message = "签署人名称不能为空")
private String name;
/**
* 身份证号码/统⼀信⽤代码
*/
@NotBlank(message = "签署人证件信息不能为空")
private String idcard;
/**
* 签章图⽚⽂件
*/
@NotBlank(message = "签章图⽚⽂件信息不能为空")
private String img;
/**
* 个⼈传⼿机号码,企业传法⼈⼿机号码/公司简称的拼⾳⾸字⺟ 如葫芦娃:hlw
*/
@NotBlank(message = "手机号不能为空")
private String phone;
/**
* 该值控制骑缝章位置 ⼤于100 表示需要签署骑缝章 双⽅骑缝章 位置间隔建议⼤于100 最⼤不能超过650
*/
private Integer gapMargin;
/**
* 签署区域 (普通签署方式)
*/
private List<Area> areas;
/**
* 签署关键字 (关键字签署方式)
*/
private String key;
/**
* 签章签署在距离关键字距离 正数(往右)负数(往左) (关键字签署方式)
*/
private Integer marginLeft;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class Area {
@NotNull(message = "签署区域左下⻆点X坐标不能为空")
private Integer x1;
@NotNull(message = "签署区域左下⻆点Y坐标不能为空")
private Integer y1;
@NotNull(message = "签署区域右上⻆点X坐标不能为空")
private Integer x2;
@NotNull(message = "签署区域右上⻆点Y坐标不能为空")
private Integer y2;
@NotNull(message = "签署⻚数不能为空")
private Integer page;
}
}

View File

@@ -0,0 +1,17 @@
package com.senmesh.sdk.fangxinqian.dto;
import lombok.Data;
@Data
public class ContractResponseDTO extends FxqResponseDTO<String> {
/**
* 文件base64或云链接
*/
private String data;
@Override
protected String handleData() {
return this.data;
}
}

View File

@@ -0,0 +1,23 @@
package com.senmesh.sdk.fangxinqian.dto;
import lombok.*;
import javax.validation.constraints.NotNull;
/**
* 区块链出证请求DTO
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class EvidenceGetRequestDTO extends FxqRequestDTO {
private static final long serialVersionUID = 7354207669664708465L;
/**
* 合同区块链存证时的回执
*/
@NotNull(message = "回执不能为空")
private String evidenceID;
}

View File

@@ -0,0 +1,17 @@
package com.senmesh.sdk.fangxinqian.dto;
import lombok.Data;
@Data
public class EvidenceGetResponseDTO extends FxqResponseDTO<String> {
/**
* 证据链上地址
*/
private String data;
@Override
protected String handleData() {
return this.data;
}
}

View File

@@ -0,0 +1,96 @@
package com.senmesh.sdk.fangxinqian.dto;
import lombok.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* 区块链存证请求DTO
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class EvidenceSaveRequestDTO extends FxqRequestDTO {
private static final long serialVersionUID = 7354207669664708465L;
/**
* 合同⽂件(base64/云存储⽂件链接)
*/
@NotBlank(message = "合同⽂件不能为空")
private String contract;
/**
* 合同名称
*/
@NotBlank(message = "合同名称不能为空")
private String title;
/**
* ⾏业类型
* 1 政务⺠⽣
* 2 保险
* 3 银⾏
* 4 消费⾦融-资产
* 5 消费⾦融-资⾦
* 6 持牌⼩贷
* 7 医疗
* 8 教育
* 9 出⾏与交通
* 10 ⽣活服务
* 11 通信与运营商
* 12 旅游与酒店
* 13 快递与邮政
* 99 其他
*/
@NotBlank(message = "⾏业类型不能为空")
private String industry;
/**
* 签署⼈信息
*/
@NotNull(message = "签署⼈列表")
private List<UserInfo> userInfos;
/**
* 合同签署⼈列表
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class UserInfo {
/**
* 真实姓名/公司名称
*/
@NotBlank(message = "签署人姓名不能为空")
private String userName;
/**
* ⽤户类型 0.个⼈ 1.企业
*/
@NotBlank(message = "⽤户类型不能为空")
private String customerType;
/**
* 证件类型 具体参考类型列表
* 0 居⺠身份证
* 1 护照
* 3 ⼯商登记证
* C 台湾居⺠来往⼤陆通⾏证
* P 外国⼈永久居留证
* Z 其它
*/
@NotBlank(message = "证件类型不能为空")
private String identificationType;
/**
* 证件号码
*/
@NotBlank(message = "证件号码不能为空")
private String identificationNo;
}
}

View File

@@ -0,0 +1,17 @@
package com.senmesh.sdk.fangxinqian.dto;
import lombok.Data;
@Data
public class EvidenceSaveResponseDTO extends FxqResponseDTO<String> {
/**
* 区块链存证业务回执 这个需要⾃⾏保存 出证需要⽤到
*/
private String data;
@Override
protected String handleData() {
return this.data;
}
}

View File

@@ -0,0 +1,27 @@
package com.senmesh.sdk.fangxinqian.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 放心签请求父类dto
*
* @author sr on 2020-04-09
*/
@Data
@NoArgsConstructor
public class FxqRequestDTO implements Serializable {
private static final long serialVersionUID = 3960499271644654446L;
/**
* id
**/
private String appId;
/**
* secret
**/
private String appSecret;
}

View File

@@ -0,0 +1,76 @@
package com.senmesh.sdk.fangxinqian.dto;
import com.senmesh.common.AlitaResult;
import com.senmesh.sdk.fangxinqian.constant.FxqConstants;
import com.senmesh.sdk.fangxinqian.constant.FxqErrorCodeEnum;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.util.StringUtils;
import java.io.Serializable;
/**
* 放心签返回
*
* @param <T>
* @author sr on 2020-04-09
*/
@Data
@NoArgsConstructor
public class FxqResponseDTO<T> implements Serializable {
/**
*
**/
private static final long serialVersionUID = -4576000729533850612L;
/**
* 错误码
**/
private String code;
/**
* 序列号(每次调用接口返回的唯一值,seqNo 如有接口问题,请提供此值)
**/
private String seqNo;
/**
* 错误信息 1
**/
private String message;
/**
* 错误信息 2
*/
private String msg;
public static FxqResponseDTO buildCommonError() {
FxqResponseDTO fxqResponseDTO = new FxqResponseDTO();
fxqResponseDTO.setCode("999");
return fxqResponseDTO;
}
/**
* 返回结果处理
*
* @return
*/
public AlitaResult<T> handleResult() {
if (FxqConstants.SUC_CODE.equals(this.getCode())) {
return AlitaResult.success(handleData());
} else {
return AlitaResult.error(FxqErrorCodeEnum.INVOKE_RETURN_ERROR.getCode(),
StringUtils.isEmpty(this.getMsg()) ?
StringUtils.isEmpty(this.getMessage()) ? FxqErrorCodeEnum.INVOKE_RETURN_ERROR.getMsg() : this.getMessage()
: this.getMsg());
}
}
/**
* 子类DTO实现 转换为AlitaResult时
* 通过 handleData()决定转换为AlitaResult的data返回什么
*
* @return
*/
protected T handleData() {
return null;
}
}

View File

@@ -0,0 +1,34 @@
package com.senmesh.sdk.fangxinqian.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
/**
* @author chenyun
* @description [ 放心签 ] 公章生成请求DTO
* @date 2020/8/14 11:33
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class GovernmentAuthRequestDTO extends FxqRequestDTO {
private static final long serialVersionUID = -5777141264861824696L;
/**
* 企业名称
*/
@NotNull(message = "企业名称不能为空")
private String companyName;
/**
* 企业类型 0.企业 1.个体⼯商户
*/
@NotNull(message = "企业类型不能为空")
private String companyType;
}

View File

@@ -0,0 +1,123 @@
package com.senmesh.sdk.fangxinqian.dto;
import lombok.Data;
import java.io.Serializable;
import java.util.Map;
import java.util.Optional;
@Data
public class GovernmentAuthResponseDTO extends FxqResponseDTO<GovernmentAuthResponseDTO.GovernmentAuthResponseDataDTO> {
private String status;
/**
* 返回实体
*/
private Map<String, GovernmentAuthResponseDataDTO> data;
@Override
protected GovernmentAuthResponseDataDTO handleData() {
return Optional.ofNullable(this.getData())
.map(result -> Optional.ofNullable(result.get("basic")).orElse(null))
.orElse(null);
}
@Data
public static class GovernmentAuthResponseDataDTO implements Serializable {
private static final long serialVersionUID = -3235649555399151281L;
private String esdate;
/**
* 原注册号
*/
private String regno;
/**
* 统一信用代码
*/
private String creditcode;
/**
* 地址
*/
private String dom;
/**
* 经营业务范围
*/
private String zsopscope;
/**
* 实收资本
*/
private String reccap;
/**
* 原注册号
*/
private String oriregno;
/**
* 企业英文名
*/
private String entnameeng;
/**
* 企业类型
*/
private String enttype;
/**
* 最后年检度
*/
private String ancheyear;
/**
* 经营期限至
*/
private String opto;
/**
* 经营企业自
*/
private String opfrom;
/**
* 注册资本币种
*/
private String regcapcur;
/**
* 组织机构代码
*/
private String orgcodes;
/**
* 注销日期
*/
private String candate;
/**
* 企业名称
*/
private String entname;
/**
* 实收资本
*/
private String regcap;
/**
* 登记机关
*/
private String regorg;
/**
* 吊销日期
*/
private String revdate;
/**
* 经营状态
*/
private String entstatus;
/**
* 许可经营项目
*/
private String abuitem;
/**
* 注册地址编码
*/
private String regorgcode;
/**
* 法人姓名
*/
private String frname;
/**
*
*/
private String apprdate;
}
}

View File

@@ -0,0 +1,60 @@
package com.senmesh.sdk.fangxinqian.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* @author chenyun
* @description [ 放心签 ] 公章生成请求DTO
* @date 2020/8/14 11:33
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OfficialSealGenerateRequestDTO implements Serializable {
private static final long serialVersionUID = -4020535227323920801L;
/**
* 系统预留⼿机号
*/
private String phone;
/**
* 公司名称
*/
@NotNull(message = "公司名称不能为空")
private String companyName;
/**
* 公章类型 默认圆形 0:圆形 ,1:椭圆形
*/
@NotNull(message = "公章类型不能为空")
private String serviceType;
/**
* 公章颜⾊ , 默认红⾊ ,0:红⾊ ,1:蓝⾊ ,2:⿊⾊
*/
private String color;
/**
* 公章字体 , 默认宋体 ,0:宋体 ,1:楷体 ,2:正⽅⿊体
*/
private String font;
/**
* 公章下弦⽂
*/
private String serNo;
/**
* 公章副标题
*/
private String title;
}

View File

@@ -0,0 +1,49 @@
package com.senmesh.sdk.fangxinqian.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* @author chenyun
* @description [ 放心签 ] 个人章生成请求DTO
* @date 2020/8/17 10:41
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PersonalSealGenerateRequestDTO implements Serializable {
private static final long serialVersionUID = -4020535227323920801L;
/**
* 系统预留⼿机号
*/
private String phone;
/**
* 个⼈签章名称
*/
@NotNull(message = "个⼈签章名称不能为空")
private String fontText;
/**
* 签章颜⾊ , 默认红⾊ ,1: 红⾊ ,2: ⿊⾊ ,3: 蓝⾊
*/
private Integer colorTag;
/**
* 签章字体 , 默认⽅正⿊体 ,1: ⽅正⿊体 ,2: 仿宋 ,3: 楷体
*/
private Integer fontFamilyTag;
/**
* 签章类型 , 默认⻓⽅形 ; 1: ⻓⽅形 , 2 正⽅形
*/
private Integer shape;
}

View File

@@ -0,0 +1,19 @@
package com.senmesh.sdk.fangxinqian.dto;
import com.senmesh.common.annotation.Mask;
import lombok.Data;
@Data
public class PersonalSealGenerateResponseDTO extends FxqResponseDTO<String> {
/**
* 公章/个人章 图片 base64
*/
@Mask
private String data;
@Override
protected String handleData() {
return this.data;
}
}

View File

@@ -0,0 +1,34 @@
package com.senmesh.sdk.fangxinqian.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
/**
* @author chenyun
* @description [ 放心签 ] 公章生成请求DTO
* @date 2020/8/14 11:33
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RealnameAuthRequestDTO extends FxqRequestDTO {
private static final long serialVersionUID = -5777141264861824696L;
/**
* 系统预留⼿机号
*/
@NotNull(message = "姓名不能为空")
private String name;
/**
* 公司名称
*/
@NotNull(message = "身份证号码不能为空")
private String identityNumber;
}

View File

@@ -0,0 +1,31 @@
package com.senmesh.sdk.fangxinqian.dto;
import com.senmesh.sdk.fangxinqian.enums.RealnameResultEnum;
import lombok.Data;
import java.io.Serializable;
import java.util.Optional;
@Data
public class RealnameAuthResponseDTO extends FxqResponseDTO<Boolean> {
private String status;
/**
* 实名认证结果 1:实名通过 2:实名不通过
*/
private RealnameAuthResponseDataDTO data;
@Override
protected Boolean handleData() {
return Optional.ofNullable(this.getData())
.map(result -> Optional.ofNullable(result.getResult()).orElse("").equals(RealnameResultEnum.SUC.getResult()))
.orElse(false);
}
@Data
public static class RealnameAuthResponseDataDTO implements Serializable {
private static final long serialVersionUID = -3235649555399151281L;
private String result;
}
}

View File

@@ -0,0 +1,17 @@
package com.senmesh.sdk.fangxinqian.dto;
import lombok.Data;
@Data
public class SealGenerateResponseDTO extends FxqResponseDTO<String> {
/**
* 公章/个人章 图片 base64
*/
private String baseStr;
@Override
protected String handleData() {
return this.baseStr;
}
}

View File

@@ -0,0 +1,21 @@
package com.senmesh.sdk.fangxinqian.dto;
import java.io.Serializable;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author sr on 2020-04-09
*/
@Data
@NoArgsConstructor
public class StateDataDTO implements Serializable{
/** **/
private static final long serialVersionUID = -4608569342053995450L;
/** 状态 **/
private String state;
}

View File

@@ -0,0 +1,64 @@
package com.senmesh.sdk.fangxinqian.dto;
import com.senmesh.common.annotation.Mask;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.List;
/**
* @author chenyun
* @description [ 放心签 ] 合同替换关键字请求DTO
* @date 2020/8/17 11:15
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TextReplaceRequestDTO implements Serializable {
private static final long serialVersionUID = -4020535227323920801L;
/**
* 系统预留⼿机号
*/
private String phone;
/**
* 待替换的 base64 ⽂档
*/
@Mask
@NotNull(message = "个⼈签章名称不能为空")
private String fileBase64;
/**
* ⽂件类型暂时只⽀持以下三种
* 1:pdf 2:doc 3.docx
* 不传默认1
*/
private String fileType;
/** 待替换内容集合 **/
private List<KeyValueBO> keyValues;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class KeyValueBO {
/**
* 关键字key
*/
private String oldText;
/**
* 关键字value
*/
private String newText;
}
}

View File

@@ -0,0 +1,19 @@
package com.senmesh.sdk.fangxinqian.dto;
import com.senmesh.common.annotation.Mask;
import lombok.Data;
@Data
public class TextReplaceResponseDTO extends FxqResponseDTO<String> {
/**
* 文档 base64
*/
@Mask
private String data;
@Override
protected String handleData() {
return this.data;
}
}

View File

@@ -0,0 +1,26 @@
package com.senmesh.sdk.fangxinqian.enums;
/**
* 实名认证状态枚举类
*/
public enum RealnameResultEnum {
SUC("1", "实名通过"),
FAIL("2", "实名不通过");
private String result;
private String message;
RealnameResultEnum(String result, String message) {
this.result = result;
this.message = message;
}
public String getResult() {
return result;
}
public String getMessage() {
return message;
}
}

View File

@@ -0,0 +1,116 @@
package com.senmesh.sdk.fangxinqian.service;
import com.senmesh.common.AlitaResult;
import com.senmesh.sdk.fangxinqian.dto.*;
import org.springframework.validation.annotation.Validated;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.validation.groups.Default;
/**
* 放心签
*
* @author sr on 2020-04-09
*/
@Validated(Default.class)
public interface FangXinQianService {
String BEAN_ID = "sdk.fangXinQianService";
String MOCK_BEAN_ID = "mock.fangXinQianService";
/**
* 银行卡三要素
*
* @param bankCardThreeRequestDto
* @return success-false真实调用第三方未成功,未拿到返回值;
* success-true获取到第三方返回,data-true校验成功,data-false校验不一致并返回失败原因(msg)
* @author sr on 2020-04-10
*/
AlitaResult<Boolean> checkBankCardThree(@NotNull @Valid BankCardThreeRequestDTO bankCardThreeRequestDto);
/**
* 银行卡四要素
*
* @param bankCardFourRequestDto
* @return success-false真实调用第三方未成功,未拿到返回值;
* success-true获取到第三方返回,data-true校验成功,data-false校验不一致并返回失败原因(msg)
* @author sr on 2020-05-22
*/
AlitaResult<Boolean> checkBankCardFour(@NotNull @Valid BankCardFourRequestDTO bankCardFourRequestDto);
/**
* 公章生成
*
* @param officialSealGenerateRequestDTO
* @return base64
*/
AlitaResult<String> generateOfficialSeal(@NotNull @Valid OfficialSealGenerateRequestDTO officialSealGenerateRequestDTO);
/**
* 个人章生成
*
* @param personalSealGenerateRequestDTO
* @return
*/
AlitaResult<String> generatePersonalSeal(@NotNull @Valid PersonalSealGenerateRequestDTO personalSealGenerateRequestDTO);
/**
* 文档关键字替换
*
* @param textReplaceRequestDTO
* @return
*/
AlitaResult<String> textReplace(@NotNull @Valid TextReplaceRequestDTO textReplaceRequestDTO);
/**
* 实名认证
*
* @param realnameAuthRequestDTO
* @return
*/
AlitaResult<Boolean> realnameAuth(@NotNull @Valid RealnameAuthRequestDTO realnameAuthRequestDTO);
/**
* 工商信息核验
*
* @param governmentAuthRequestDTO
* @return
*/
AlitaResult<GovernmentAuthResponseDTO.GovernmentAuthResponseDataDTO> governmentAuth(@NotNull @Valid GovernmentAuthRequestDTO governmentAuthRequestDTO);
/**
* 合同签署 (普通签署)
*
* @param contractRequestDTO
* @return
*/
AlitaResult<String> contractCommonSign(@NotNull @Valid ContractRequestDTO contractRequestDTO);
/**
* 合同签署 (关键字签署)
*
* @param contractRequestDTO
* @return
*/
AlitaResult<String> contractKeySign(@NotNull @Valid ContractRequestDTO contractRequestDTO);
/**
* 存证接⼝
* 存证成功的合同默认30s以后才能出证,如果太早出证会提示证据不存在
*
* @param evidenceSaveRequestDTO
* @return
*/
AlitaResult<String> evidenceSave(@NotNull @Valid EvidenceSaveRequestDTO evidenceSaveRequestDTO);
/**
* 出证接口
*
* @param evidenceGetRequestDTO
* @return
*/
AlitaResult<String> evidenceGet(@NotNull @Valid EvidenceGetRequestDTO evidenceGetRequestDTO);
}

View File

@@ -0,0 +1,247 @@
package com.senmesh.sdk.fangxinqian.service.impl;
import com.senmesh.common.AlitaResult;
import com.senmesh.common.annotation.CheckAndMock;
import com.senmesh.sdk.common.constant.SdkConstants;
import com.senmesh.sdk.fangxinqian.config.FxqCommonProperties;
import com.senmesh.sdk.fangxinqian.config.FxqContractProperties;
import com.senmesh.sdk.fangxinqian.config.FxqProperties;
import com.senmesh.sdk.fangxinqian.constant.BankCardFourStateEnum;
import com.senmesh.sdk.fangxinqian.constant.BankCardThreeStateEnum;
import com.senmesh.sdk.fangxinqian.constant.FxqConstants;
import com.senmesh.sdk.fangxinqian.constant.FxqErrorCodeEnum;
import com.senmesh.sdk.fangxinqian.dto.*;
import com.senmesh.sdk.fangxinqian.service.FangXinQianService;
import com.senmesh.sdk.fangxinqian.util.FxqUtils;
import com.senmesh.sdk.fangxinqian.util.HttpUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author sr on 2020-04-09
*/
@Slf4j
@Service(FangXinQianService.BEAN_ID)
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class FangXinQianServiceImpl implements FangXinQianService {
private final FxqProperties fxqProperties;
@Override
public AlitaResult<String> generateOfficialSeal(OfficialSealGenerateRequestDTO officialSealGenerateRequestDTO) {
if (StringUtils.isEmpty(officialSealGenerateRequestDTO.getPhone())) {
officialSealGenerateRequestDTO.setPhone(fxqProperties.getPhone());
}
return HttpUtil
.execute(fxqProperties.getDomain().concat(fxqProperties.getOfficialSealUri()),
officialSealGenerateRequestDTO, SealGenerateResponseDTO.class)
.handleResult();
}
@Override
public AlitaResult<String> generatePersonalSeal(PersonalSealGenerateRequestDTO personalSealGenerateRequestDTO) {
if (StringUtils.isEmpty(personalSealGenerateRequestDTO.getPhone())) {
personalSealGenerateRequestDTO.setPhone(fxqProperties.getPhone());
}
return HttpUtil
.execute(fxqProperties.getDomain().concat(fxqProperties.getPersonalSealUri()),
personalSealGenerateRequestDTO, PersonalSealGenerateResponseDTO.class)
.handleResult();
}
@Override
public AlitaResult<String> textReplace(TextReplaceRequestDTO textReplaceRequestDTO) {
if (StringUtils.isEmpty(textReplaceRequestDTO.getPhone())) {
textReplaceRequestDTO.setPhone(fxqProperties.getPhone());
}
return HttpUtil
.execute(fxqProperties.getDomain().concat(fxqProperties.getTextReplaceUri()),
textReplaceRequestDTO, TextReplaceResponseDTO.class)
.handleResult();
}
@Override
@CheckAndMock(mockClass = MockFangXinQianServiceImpl.class,
propertyPrefix = FxqProperties.REALNAME_AUTH_PREFIX)
public AlitaResult<Boolean> realnameAuth(RealnameAuthRequestDTO realnameAuthRequestDTO) {
FxqCommonProperties fxqCommonProperties = fxqProperties.getRealName();
// 校验部分
if (fxqCommonProperties == null) {
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE,
FxqConstants.PROPERTIES_NOT_SET);
}
if (!FxqUtils.dealAppIdAndSecret(fxqCommonProperties, realnameAuthRequestDTO)) {
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE,
FxqConstants.ID_SECRET_NOT_ENOUGH);
}
//执行
return HttpUtil
.execute(fxqProperties.getDomain().concat(fxqCommonProperties.getUrl()),
realnameAuthRequestDTO, RealnameAuthResponseDTO.class)
.handleResult();
}
@Override
@CheckAndMock(mockClass = MockFangXinQianServiceImpl.class,
propertyPrefix = FxqProperties.GOVERNMENT_AUTH_PREFIX)
public AlitaResult<GovernmentAuthResponseDTO.GovernmentAuthResponseDataDTO> governmentAuth(GovernmentAuthRequestDTO governmentAuthRequestDTO) {
FxqCommonProperties fxqCommonProperties = fxqProperties.getGovernment();
// 校验部分
if (fxqCommonProperties == null) {
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE,
FxqConstants.PROPERTIES_NOT_SET);
}
if (!FxqUtils.dealAppIdAndSecret(fxqCommonProperties, governmentAuthRequestDTO)) {
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE,
FxqConstants.ID_SECRET_NOT_ENOUGH);
}
//执行
return HttpUtil
.execute(fxqProperties.getDomain().concat(fxqCommonProperties.getUrl()),
governmentAuthRequestDTO, GovernmentAuthResponseDTO.class)
.handleResult();
}
@Override
@CheckAndMock(mockClass = MockFangXinQianServiceImpl.class,
propertyPrefix = FxqProperties.COMMON_SIGN_PREFIX)
public AlitaResult<String> contractCommonSign(ContractRequestDTO contractRequestDTO) {
FxqContractProperties contract = fxqProperties.getContract();
FxqCommonProperties fxqCommonProperties = contract.build(contract.getCommonSign());
// 校验部分
if (fxqCommonProperties == null) {
return AlitaResult.error(
SdkConstants.SDK_INVOKE_NOT_REACH_CODE, FxqConstants.PROPERTIES_NOT_SET);
}
if (!FxqUtils.dealAppIdAndSecret(fxqCommonProperties, contractRequestDTO)) {
return AlitaResult.error(
SdkConstants.SDK_INVOKE_NOT_REACH_CODE, FxqConstants.ID_SECRET_NOT_ENOUGH);
}
// 执行
return HttpUtil
.execute(fxqProperties.getDomain().concat(fxqCommonProperties.getUrl()),
contractRequestDTO, ContractResponseDTO.class)
.handleResult();
}
@Override
@CheckAndMock(mockClass = MockFangXinQianServiceImpl.class,
propertyPrefix = FxqProperties.KEY_SIGN_PREFIX)
public AlitaResult<String> contractKeySign(ContractRequestDTO contractRequestDTO) {
FxqContractProperties contract = fxqProperties.getContract();
FxqCommonProperties fxqCommonProperties = contract.build(contract.getKeySign());
// 校验部分
if (fxqCommonProperties == null) {
return AlitaResult.error(
SdkConstants.SDK_INVOKE_NOT_REACH_CODE, FxqConstants.PROPERTIES_NOT_SET);
}
if (!FxqUtils.dealAppIdAndSecret(fxqCommonProperties, contractRequestDTO)) {
return AlitaResult.error(
SdkConstants.SDK_INVOKE_NOT_REACH_CODE, FxqConstants.ID_SECRET_NOT_ENOUGH);
}
// 执行
return HttpUtil
.execute(
fxqProperties.getDomain().concat(fxqCommonProperties.getUrl()),
contractRequestDTO, ContractResponseDTO.class)
.handleResult();
}
@Override
@CheckAndMock(mockClass = MockFangXinQianServiceImpl.class,
propertyPrefix = FxqProperties.EVIDENCE_SAVE_PREFIX)
public AlitaResult<String> evidenceSave(EvidenceSaveRequestDTO evidenceSaveRequestDTO) {
FxqContractProperties contract = fxqProperties.getContract();
FxqCommonProperties fxqCommonProperties = contract.build(contract.getEvidenceSave());
// 校验部分
if (fxqCommonProperties == null) {
return AlitaResult.error(
SdkConstants.SDK_INVOKE_NOT_REACH_CODE, FxqConstants.PROPERTIES_NOT_SET);
}
if (!FxqUtils.dealAppIdAndSecret(fxqCommonProperties, evidenceSaveRequestDTO)) {
return AlitaResult.error(
SdkConstants.SDK_INVOKE_NOT_REACH_CODE, FxqConstants.ID_SECRET_NOT_ENOUGH);
}
// 执行
return HttpUtil
.execute(
fxqProperties.getDomain().concat(fxqCommonProperties.getUrl()),
evidenceSaveRequestDTO, ContractResponseDTO.class)
.handleResult();
}
@Override
@CheckAndMock(mockClass = MockFangXinQianServiceImpl.class,
propertyPrefix = FxqProperties.EVIDENCE_GET_PREFIX)
public AlitaResult<String> evidenceGet(EvidenceGetRequestDTO evidenceGetRequestDTO) {
FxqContractProperties contract = fxqProperties.getContract();
FxqCommonProperties fxqCommonProperties = contract.build(contract.getEvidenceGet());
// 校验部分
if (fxqCommonProperties == null) {
return AlitaResult.error(
SdkConstants.SDK_INVOKE_NOT_REACH_CODE, FxqConstants.PROPERTIES_NOT_SET);
}
if (!FxqUtils.dealAppIdAndSecret(fxqCommonProperties, evidenceGetRequestDTO)) {
return AlitaResult.error(
SdkConstants.SDK_INVOKE_NOT_REACH_CODE, FxqConstants.ID_SECRET_NOT_ENOUGH);
}
// 执行
return HttpUtil
.execute(
fxqProperties.getDomain().concat(fxqCommonProperties.getUrl()),
evidenceGetRequestDTO, ContractResponseDTO.class)
.handleResult();
}
@Override
@CheckAndMock(mockClass = MockFangXinQianServiceImpl.class,
propertyPrefix = FxqProperties.BANK_CARD_THREE_PREFIX)
public AlitaResult<Boolean> checkBankCardThree(BankCardThreeRequestDTO bankCardThreeRequestDto) {
return this.check(bankCardThreeRequestDto, fxqProperties.getBankCard3(),
BankCardThreeResponseDTO.class);
}
@Override
@CheckAndMock(mockClass = MockFangXinQianServiceImpl.class,
propertyPrefix = FxqProperties.BANK_CARD_FOUR_PREFIX)
public AlitaResult<Boolean> checkBankCardFour(BankCardFourRequestDTO bankCardFourRequestDto) {
return this.check(bankCardFourRequestDto, fxqProperties.getBankCard4(),
BankCardFourResponseDTO.class);
}
private <T extends FxqResponseDTO> AlitaResult<Boolean> check(FxqRequestDTO fxqRequestDto,
FxqCommonProperties fxqCommonProperties,
Class<T> responseClazz) {
// 校验部分
if (fxqCommonProperties == null) {
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE,
FxqConstants.PROPERTIES_NOT_SET);
}
if (!FxqUtils.dealAppIdAndSecret(fxqCommonProperties, fxqRequestDto)) {
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE,
FxqConstants.ID_SECRET_NOT_ENOUGH);
}
// 执行
FxqResponseDTO responseDto = HttpUtil.execute(fxqProperties.getDomain().concat(fxqCommonProperties.getUrl()),
fxqRequestDto, responseClazz);
// 返回结果校验
if (!FxqConstants.SUC_CODE.equals(responseDto.getCode())) {
return AlitaResult.success(StringUtils.join(FxqErrorCodeEnum.INVOKE_RETURN_ERROR.getMsg(),
responseDto.getMessage()), false);
}
if (responseClazz == BankCardThreeResponseDTO.class) {
String state = ((BankCardThreeResponseDTO) responseDto).getData().getState();
return BankCardThreeStateEnum.dealState(state);
}
// 处理验证结果
return BankCardFourStateEnum.dealState(((BankCardFourResponseDTO) responseDto).getData().getState());
}
}

View File

@@ -0,0 +1,86 @@
package com.senmesh.sdk.fangxinqian.service.impl;
import com.senmesh.common.AlitaResult;
import com.senmesh.sdk.fangxinqian.dto.*;
import com.senmesh.sdk.fangxinqian.service.FangXinQianService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
/**
* @author sr on 2020-04-09
*/
@Service(FangXinQianService.MOCK_BEAN_ID)
@Slf4j
public class MockFangXinQianServiceImpl implements FangXinQianService {
@Override
public AlitaResult<Boolean> checkBankCardThree(
@NotNull @Valid BankCardThreeRequestDTO bankCardThreeRequestDto) {
log.info("fxq checkBankCardThree mock...");
return AlitaResult.success(true);
}
@Override
public AlitaResult<Boolean> checkBankCardFour(@NotNull @Valid BankCardFourRequestDTO bankCardFourRequestDto) {
log.info("fxq checkBankCardFour mock...");
return AlitaResult.success(true);
}
@Override
public AlitaResult<String> generateOfficialSeal(@NotNull @Valid OfficialSealGenerateRequestDTO officialSealGenerateRequestDTO) {
log.info("fxq generateOfficialSeal mock...");
return AlitaResult.success("");
}
@Override
public AlitaResult<String> generatePersonalSeal(@NotNull @Valid PersonalSealGenerateRequestDTO personalSealGenerateRequestDTO) {
log.info("fxq generatePersonalSeal mock...");
return AlitaResult.success("");
}
@Override
public AlitaResult<String> textReplace(@NotNull @Valid TextReplaceRequestDTO textReplaceRequestDTO) {
log.info("fxq textReplace mock...");
return AlitaResult.success("");
}
@Override
public AlitaResult<Boolean> realnameAuth(@NotNull @Valid RealnameAuthRequestDTO realnameAuthRequestDTO) {
log.info("fxq realnameAuth mock...");
return AlitaResult.success(true);
}
@Override
public AlitaResult<GovernmentAuthResponseDTO.GovernmentAuthResponseDataDTO> governmentAuth(@NotNull @Valid GovernmentAuthRequestDTO governmentAuthRequestDTO) {
log.info("fxq governmentAuth mock...");
return AlitaResult.success(new GovernmentAuthResponseDTO.GovernmentAuthResponseDataDTO());
}
@Override
public AlitaResult<String> contractCommonSign(@NotNull @Valid ContractRequestDTO contractRequestDTO) {
log.info("fxq contractCommonSign mock...");
return AlitaResult.success("https://huluwa-ec.oss-accelerate.aliyuncs.com/20200825/20200825174051_2913.pdf?Expires=4751948451&OSSAccessKeyId=HLUmOSIDpYentPOt&Signature=RB%2FFQgM7dJyBac4DMSG0YZYz3ao%3D");
}
@Override
public AlitaResult<String> contractKeySign(@NotNull @Valid ContractRequestDTO contractRequestDTO) {
log.info("fxq contractKeySign mock...");
return AlitaResult.success("https://huluwa-ec.oss-accelerate.aliyuncs.com/20200825/20200825174051_2913.pdf?Expires=4751948451&OSSAccessKeyId=HLUmOSIDpYentPOt&Signature=RB%2FFQgM7dJyBac4DMSG0YZYz3ao%3D");
}
@Override
public AlitaResult<String> evidenceSave(@NotNull @Valid EvidenceSaveRequestDTO evidenceSaveRequestDTO) {
log.info("fxq evidenceSave mock...");
return AlitaResult.success("");
}
@Override
public AlitaResult<String> evidenceGet(@NotNull @Valid EvidenceGetRequestDTO evidenceGetRequestDTO) {
log.info("fxq evidenceGet mock...");
return AlitaResult.success("");
}
}

View File

@@ -0,0 +1,62 @@
package com.senmesh.sdk.fangxinqian.util;
import org.apache.commons.lang3.StringUtils;
import com.senmesh.sdk.fangxinqian.config.FxqCommonProperties;
import com.senmesh.sdk.fangxinqian.dto.FxqRequestDTO;
/**
* 工具类
*
* @author sr on 2020-04-09
*/
public final class FxqUtils {
/**
* 私有
*/
private FxqUtils() {
throw new IllegalStateException("Utility class");
}
/**
* 处理appId和appSecret参数
*
* @param <T>
* @param fxqCommonProperties
* @param fxqRequestDto
* @author sr on 2020-04-09
*/
public static <T extends FxqRequestDTO> boolean dealAppIdAndSecret(FxqCommonProperties fxqCommonProperties,
T fxqRequestDto) {
String appId = fxqRequestDto.getAppId();
String appSecret = fxqRequestDto.getAppSecret();
boolean enable = enableFxq(fxqCommonProperties);
if (StringUtils.isBlank(appId) && enable) {
appId = fxqCommonProperties.getAppId();
}
if (StringUtils.isBlank(appSecret) && enable) {
appSecret = fxqCommonProperties.getAppSecret();
}
if (StringUtils.isBlank(appId) || StringUtils.isBlank(appSecret)) {
return false;
}
fxqRequestDto.setAppId(appId);
fxqRequestDto.setAppSecret(appSecret);
return true;
}
/**
* 是否开启放心签接口
*
* @param fxqCommonProperties
* @return
* @author sr on 2020-04-21
*/
public static boolean enableFxq(FxqCommonProperties fxqCommonProperties) {
return fxqCommonProperties != null && fxqCommonProperties.getEnable();
}
}

View File

@@ -0,0 +1,58 @@
package com.senmesh.sdk.fangxinqian.util;
import com.senmesh.common.util.JsonUtils;
import com.senmesh.sdk.fangxinqian.dto.FxqResponseDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.web.client.RestTemplate;
@Slf4j
@Component
public class HttpUtil<T, R> {
private static RestTemplate restTemplate;
@Autowired
public HttpUtil(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
/**
* Http 通用请求封装
*
* @param url 请求地址
* @param requestDto 请求实体
* @param responseClazz 返回实体Class
* @param <T>
* @param <R>
* @return
*/
public static <T, R extends FxqResponseDTO> FxqResponseDTO execute(String url, T requestDto, Class<R> responseClazz) {
ResponseEntity<R> response;
StopWatch stopWatch = new StopWatch();
stopWatch.start();
try {
log.debug("fangxinqian request url :{}", url);
log.info("fangxinqian request requestDto :{}", JsonUtils.toJsonString(requestDto));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity request = new HttpEntity<>(requestDto, headers);
response = restTemplate.postForEntity(url, request, responseClazz);
log.info("fangxinqian {}:{}", responseClazz.getName(), JsonUtils.toJsonString(response));
} catch (Exception e) {
log.error("fangxinqian {} invoke error:{}", requestDto.getClass().getName(),
e);
stopWatch.stop();
return FxqResponseDTO.buildCommonError();
}
stopWatch.stop();
log.info("fangxinqian consuming {} s", stopWatch.getTotalTimeSeconds());
return JsonUtils.objToClassObj(response.getBody(), responseClazz);
}
}

View File

@@ -0,0 +1,25 @@
package com.senmesh.sdk.mbti.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@ConfigurationProperties(prefix = MbtiProperties.PREFIX)
@Data
@Component
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MbtiProperties {
public static final String PREFIX = "mbti";
private String urlPrefix;
private String appId;
private String appKey;
}

View File

@@ -0,0 +1,39 @@
package com.senmesh.sdk.mbti.mobel;
import org.springframework.core.ParameterizedTypeReference;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class AnswerReq extends MbtiTokenReq<MbtiRes<AnswerRes>>{
/** **/
private static final long serialVersionUID = 1L;
private static ParameterizedTypeReference<MbtiRes<AnswerRes>> type =
new ParameterizedTypeReference<MbtiRes<AnswerRes>>() {};
private String liangbiaoId;
private String userName;
private String userEmail;
private AnswerReqDTO answerData;
@Override
public String getUri() {
return "submit";
}
@Override
public ParameterizedTypeReference<MbtiRes<AnswerRes>> getResponseType() {
return type;
}
}

Some files were not shown because too many files have changed in this diff Show More