package com.ydtech.modules.order.components; import com.ydtech.config.properties.ZjApiConfigurationProperties; import com.ydtech.exception.SystemException; import com.ydtech.modules.order.constants.OrderCacheConstant; import com.ydtech.modules.order.entity.api.zj.constants.enums.RequestUrl; import com.ydtech.modules.order.entity.api.zj.constants.enums.ResultEnum; import com.ydtech.modules.order.entity.api.zj.request.*; import com.ydtech.modules.order.entity.api.zj.response.*; import com.ydtech.modules.order.entity.config.ZjConfigureParameters; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; /** * @description: 资金财险请求 * @author: wenks * @date: 2023/8/9 16:57 **/ @Slf4j @Component public class ZijinRequestApiComponents { private static final String AUTHORIZATION = "Authorization"; private static final String ZKI_API_AUTHORIZATION = "ZKIApiAuthorization"; // 递归层级 public static final int RECURSIVE_HIERARCHY = 3; private final InsCrawlerOrderComponents insCrawlerOrderComponents; private final ZjApiConfigurationProperties zjApiConfigurationProperties; private final ConfigureParametersComponents configureParametersComponents; private final StringRedisTemplate redisTemplate; private final RedissonClient redissonClient; private static final String USER_ID = "28317480921155536850"; public ZijinRequestApiComponents(InsCrawlerOrderComponents insCrawlerOrderComponents, ZjApiConfigurationProperties zjApiConfigurationProperties, ConfigureParametersComponents configureParametersComponents, StringRedisTemplate redisTemplate, RedissonClient redissonClient) { this.insCrawlerOrderComponents = insCrawlerOrderComponents; this.zjApiConfigurationProperties = zjApiConfigurationProperties; this.configureParametersComponents = configureParametersComponents; this.redisTemplate = redisTemplate; this.redissonClient = redissonClient; } public B request(String url, String desc, T requestBody, Class responseType, HttpHeaders httpHeaders) { B b = insCrawlerOrderComponents.request(url, "紫金财险", desc, requestBody, responseType, httpHeaders); ResultEnum.verify(b.getRtnCode(), b.getRtnMsg()); return b; } public B request(RequestUrl requestUrl, T requestBody, Class responseType, HttpHeaders httpHeaders) { String url = zjApiConfigurationProperties.getUrl() + requestUrl.getUri(); return request(url, requestUrl.getDesc(), requestBody, responseType, httpHeaders); } /** * 获取 接入方 token 车险业务token * * @param zjConfigureParameters 紫金api配置 * @param httpHeaders 请求头 * @return HttpHeaders */ private HttpHeaders getToken(ZjConfigureParameters zjConfigureParameters, HttpHeaders httpHeaders) { // 1 为接入方提供获取token服务 GetAccessTokenRequest getAccessTokenRequest = new GetAccessTokenRequest(zjConfigureParameters.getAppKey(), zjConfigureParameters.getAppSecret()); GetAccessTokenResponse accessToken = getAccessToken(getAccessTokenRequest); httpHeaders.set(AUTHORIZATION, accessToken.getToken()); // 2 车险业务获取token服务 QueryTokenRequest queryTokenRequest = new QueryTokenRequest(zjConfigureParameters.getAppKey(), USER_ID); QueryTokenResponse queryTokenResponse = queryToken(queryTokenRequest, httpHeaders); httpHeaders.set(ZKI_API_AUTHORIZATION, queryTokenResponse.getToken()); // 3. 将请求的token放入redis Map map = new HashMap<>(); map.put(AUTHORIZATION, accessToken.getToken()); map.put(ZKI_API_AUTHORIZATION, queryTokenResponse.getToken()); redisTemplate.opsForHash().putAll(zjConfigureParameters.getAccessToken(), map); redisTemplate.expire(zjConfigureParameters.getAccessToken(), OrderCacheConstant.ZJ_ACCESS_TOKEN_TIME, TimeUnit.HOURS); return httpHeaders; } /** * 配置方式获取请求头 * * @param zjConfigureParameters 配置参数 * @return HttpHeaders */ public HttpHeaders getHttpHeaders(ZjConfigureParameters zjConfigureParameters, int number) { if (number <= 0) { throw new SystemException("接口请求异常,请重试!"); } number--; HttpHeaders httpHeaders = new HttpHeaders(); Map entries = redisTemplate.opsForHash().entries(zjConfigureParameters.getAccessToken()); // 缓存中不存在就去请求token if (!ObjectUtils.isEmpty(entries)) { String authorization = (String) entries.get(AUTHORIZATION); String zKIApiAuthorization = (String) entries.get(ZKI_API_AUTHORIZATION); httpHeaders.set(AUTHORIZATION, authorization); httpHeaders.set(ZKI_API_AUTHORIZATION, zKIApiAuthorization); return httpHeaders; } // 使用分布式锁 只有一个人可以访问登录 RLock lock = redissonClient.getLock(zjConfigureParameters.getAccessLock()); try { boolean isLock = lock.tryLock(1, 10000, TimeUnit.MILLISECONDS); if (isLock) { try { return this.getToken(zjConfigureParameters, httpHeaders); } finally { lock.unlock(); } } } catch (InterruptedException e) { log.debug(e.getMessage()); lock.unlock(); Thread.currentThread().interrupt(); throw new SystemException(e.getMessage()); } // 睡眠一段时间 自调用 重新获取缓存中的 header try { Thread.sleep(280); } catch (InterruptedException e) { log.debug(e.getMessage()); Thread.currentThread().interrupt(); throw new SystemException("接口请求异常,请重试!"); } return getHttpHeaders(zjConfigureParameters, number); } /** * 协议id获取请求头 * * @param agreementId 协议id * @return HttpHeaders */ public HttpHeaders getHttpHeaders(String agreementId) { ZjConfigureParameters zjConfigureParameters = configureParametersComponents.toEntity(ZjConfigureParameters.class, agreementId); return getHttpHeaders(zjConfigureParameters, RECURSIVE_HIERARCHY); } /** * 为接入方提供获取token服务 * * @param getAccessTokenRequest 紫金财险 为接入方提供获取token服务 入参实体 * @return 出参实体 */ public GetAccessTokenResponse getAccessToken(GetAccessTokenRequest getAccessTokenRequest) { String url = zjApiConfigurationProperties.getAccessTokenUrl(); GetAccessTokenResponse response = insCrawlerOrderComponents.request(url, "紫金财险", "为接入方提供获取token服务", getAccessTokenRequest, GetAccessTokenResponse.class); ResultEnum.verify(response.getRtnCode(), response.getRtnMsg()); return response; } /** * 车险业务获取token服务 * * @param queryTokenRequest 紫金财险 车险业务获取token服务 入参实体 * @return 出参实体 */ public QueryTokenResponse queryToken(QueryTokenRequest queryTokenRequest, HttpHeaders httpHeaders) { return request(RequestUrl.QUERY_TOKEN, queryTokenRequest, QueryTokenResponse.class, httpHeaders); } /** * 车型查询 * * @param modelQueryRequest 紫金财险 车型查询 入参实体 * @return 出参实体 */ public ModelQueryResponse modelQuery(ModelQueryRequest modelQueryRequest, HttpHeaders httpHeaders) { return request(RequestUrl.MODELS_QUERY, modelQueryRequest, ModelQueryResponse.class, httpHeaders); } /** * 获取车辆实际价值 * * @param queryActualValueRequest 紫金财险 获取车辆实际价值 入参实体 * @return 出参实体 */ public QueryActualValueResponse queryActualValue(QueryActualValueRequest queryActualValueRequest, HttpHeaders httpHeaders) { return request(RequestUrl.QUERY_ACTUAL_VALUE, queryActualValueRequest, QueryActualValueResponse.class, httpHeaders); } /** * 查询“车+意”中意外险方案信息 * * @param queryVehicProductsRequest 紫金财险 查询“车+意”中意外险方案信息(非摩托车险)入参实体 * @return 出参实体 */ public QueryVehicProductsResponse queryVehicleProducts(QueryVehicProductsRequest queryVehicProductsRequest, HttpHeaders httpHeaders) { return request(RequestUrl.QUERY_VEHIC_PRODUCTS, queryVehicProductsRequest, QueryVehicProductsResponse.class, httpHeaders); } /** * 保费计算 * * @param calculatePremiumRequest 紫金财险 保费计算 入参实体 * @return 出参实体 */ public CalculatePremiumResponse calculatePremium(CalculatePremiumRequest calculatePremiumRequest, HttpHeaders httpHeaders) { return request(RequestUrl.CALCULATE_PREMIUM, calculatePremiumRequest, CalculatePremiumResponse.class, httpHeaders); } /** * 文件上传 * * @param uploadFileRequest 紫金财险 文件上传 入参实体 * @return 出参实体 */ public UploadFileResponse uploadFile(UploadFileRequest uploadFileRequest, HttpHeaders httpHeaders) { return request(RequestUrl.UPLOAD_FILE, uploadFileRequest, UploadFileResponse.class, httpHeaders); } /** * 文件信息与订单关联 * * @param uploadImageInfoListRequest 紫金财险 文件信息与订单关联 入参实体 * @return 出参实体 */ public BaseResponse uploadImageInfoList(UploadImageInfoListRequest uploadImageInfoListRequest, HttpHeaders httpHeaders) { return request(RequestUrl.UPLOAD_IMAGE_INFO_LIST, uploadImageInfoListRequest, BaseResponse.class, httpHeaders); } /** * 特约查询 * * @param queryClauseDataRequest 紫金财险 特约查询 入参实体 * @return 出参实体 */ public QueryClauseDataResponse queryClauseData(QueryClauseDataRequest queryClauseDataRequest, HttpHeaders httpHeaders) { return request(RequestUrl.QUERY_CLAUSE_DATA, queryClauseDataRequest, QueryClauseDataResponse.class, httpHeaders); } /** * 提交核保 * * @param submitVerifyRequest 紫金财险 提交核保 入参实体 * @return 出参实体 */ public SubmitVerifyResponse submitVerify(SubmitVerifyRequest submitVerifyRequest, HttpHeaders httpHeaders) { return request(RequestUrl.SUBMIT_VERIFY, submitVerifyRequest, SubmitVerifyResponse.class, httpHeaders); } /** * 聚合支付服务 * * @param zbfAggregatePayRequest 紫金财险 聚合支付服务 入参实体 * @return 出参实体 */ public ZbfAggregatePayResponse zbfAggregatePay(ZbfAggregatePayRequest zbfAggregatePayRequest, HttpHeaders httpHeaders) { return request(zjApiConfigurationProperties.getPayUrl(), RequestUrl.ZBF_AGGREGATE_PAY.getDesc(), zbfAggregatePayRequest, ZbfAggregatePayResponse.class, httpHeaders); } /** * 订单详情查询服务 * * @param orderNoRequest 紫金财险 订单详情查询服务 入参实体 * @return 出参实体 */ public QueryOrderDetailResponse getOrderDetail(OrderNoRequest orderNoRequest, HttpHeaders httpHeaders) { return request(zjApiConfigurationProperties.getOrderUrl(), RequestUrl.GET_ORDER_DETAIL.getDesc(), orderNoRequest, QueryOrderDetailResponse.class, httpHeaders); } /** * 未缴费保单撤单 * * @param orderNoRequest 紫金财险 未缴费保单撤单 入参实体 * @return 出参实体 */ public void cancel(OrderNoRequest orderNoRequest, HttpHeaders httpHeaders) { request(RequestUrl.CANCEL, orderNoRequest, BaseResponse.class, httpHeaders); } /** * 生成电子保单下载 * * @param busNo 保单号 * @param busType 证件号 * @param identifyNo 单证类型 1-交强险,2-保险标志,3-商业险,4-非车险,5-批单 * @return 电子保单连接 */ public String getDownLoadDocumentUrl(String busNo, String busType, String identifyNo) { String parameter = String.format("?busNo=%s&busType=%s&identifyNo=%s", busNo, busType, identifyNo); String downLoadDocument = zjApiConfigurationProperties.getDownLoadDocument(); return downLoadDocument + parameter; } }