|
|
@@ -5,22 +5,21 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
import com.jzg.commons.constants.ProductsType;
|
|
|
import com.jzg.commons.constants.dict.InsOrderStatusEnum;
|
|
|
-import com.jzg.commons.core.page.HttpResult;
|
|
|
import com.jzg.commons.entity.po.jyxSetting;
|
|
|
import com.jzg.commons.entity.quote.vo.AccidentalDrivingVo;
|
|
|
import com.jzg.commons.entity.quote.vo.AttributionInformationVo;
|
|
|
import com.jzg.commons.entity.quote.vo.CarInfoVo;
|
|
|
import com.jzg.commons.entity.quote.vo.QuoteVo;
|
|
|
import com.jzg.commons.entity.quote.vo.aggregated.*;
|
|
|
+import com.jzg.commons.entity.quote.vo.base.LoginBase;
|
|
|
+import com.jzg.commons.entity.quote.vo.base.OrderBase;
|
|
|
+import com.jzg.commons.entity.quote.vo.image.InsuranceImageVo;
|
|
|
import com.jzg.commons.entity.vo.JyxConfigVo;
|
|
|
import com.jzg.commons.exception.SystemException;
|
|
|
import com.jzg.commons.util.StringUtils;
|
|
|
import com.jzg.quotation.commons.annotation.QuoteCrawlerService;
|
|
|
import com.jzg.quotation.commons.client.PlatformClient;
|
|
|
import com.jzg.quotation.commons.constant.InsuranceCode;
|
|
|
-import com.jzg.commons.entity.quote.vo.base.LoginBase;
|
|
|
-import com.jzg.commons.entity.quote.vo.base.OrderBase;
|
|
|
-import com.jzg.commons.entity.quote.vo.image.InsuranceImageVo;
|
|
|
import com.jzg.quotation.commons.entity.DetectLoginRequest;
|
|
|
import com.jzg.quotation.commons.entity.GetCaptchaRequest;
|
|
|
import com.jzg.quotation.commons.entity.GetCaptchaResponse;
|
|
|
@@ -39,7 +38,6 @@ import com.jzg.quotation.huatai.crawler.entity.po.HtCrawlerOrder;
|
|
|
import com.jzg.quotation.huatai.crawler.properties.HuaTaiCrawlerProperties;
|
|
|
import com.jzg.quotation.huatai.crawler.service.HtCrawlerOrderService;
|
|
|
import com.jzg.quotation.huatai.crawler.service.HuaTaiCrawlerRequest;
|
|
|
-import com.jzg.quotation.huatai.crawler.util.CookieUtils;
|
|
|
import com.jzg.quotation.huatai.crawler.util.CryptoUtil;
|
|
|
import com.jzg.quotation.huatai.crawler.util.UploadUtil;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
@@ -48,14 +46,20 @@ import org.jetbrains.annotations.NotNull;
|
|
|
import org.jsoup.Jsoup;
|
|
|
import org.jsoup.nodes.Document;
|
|
|
import org.jsoup.select.Elements;
|
|
|
-import org.springframework.http.*;
|
|
|
+import org.springframework.http.HttpEntity;
|
|
|
+import org.springframework.http.HttpHeaders;
|
|
|
+import org.springframework.http.HttpMethod;
|
|
|
+import org.springframework.http.MediaType;
|
|
|
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
|
|
import org.springframework.util.LinkedMultiValueMap;
|
|
|
import org.springframework.util.MultiValueMap;
|
|
|
import org.springframework.web.client.RestTemplate;
|
|
|
import org.springframework.web.util.UriComponentsBuilder;
|
|
|
|
|
|
-import javax.net.ssl.*;
|
|
|
+import javax.net.ssl.HttpsURLConnection;
|
|
|
+import javax.net.ssl.SSLContext;
|
|
|
+import javax.net.ssl.TrustManager;
|
|
|
+import javax.net.ssl.X509TrustManager;
|
|
|
import java.io.IOException;
|
|
|
import java.net.HttpURLConnection;
|
|
|
import java.net.InetSocketAddress;
|
|
|
@@ -67,1426 +71,1072 @@ import java.security.cert.X509Certificate;
|
|
|
import java.time.LocalDateTime;
|
|
|
import java.time.format.DateTimeFormatter;
|
|
|
import java.util.*;
|
|
|
+import java.util.function.Consumer;
|
|
|
import java.util.regex.Matcher;
|
|
|
import java.util.regex.Pattern;
|
|
|
|
|
|
/**
|
|
|
- * @description: 华泰财险 爬虫报价
|
|
|
- * @author: shenwd
|
|
|
- * @date: 2025/4/15 08:56
|
|
|
- **/
|
|
|
+ * 华泰财险爬虫报价核心实现
|
|
|
+ */
|
|
|
@Slf4j
|
|
|
@QuoteCrawlerService(value = InsuranceCode.INSURANCE_HTIC)
|
|
|
@RequiredArgsConstructor
|
|
|
public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
|
|
|
|
|
|
- // ====================== 常量定义 ======================
|
|
|
- private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36";
|
|
|
+ // ====================== 常量 ======================
|
|
|
+ private static final String UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36";
|
|
|
private static final String ACCEPT_HTML = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
|
|
|
private static final String ACCEPT_JSON = "application/json, text/javascript, */*; q=0.01";
|
|
|
- private static final String ACCEPT_ALL = "*/*";
|
|
|
private static final String ORIGIN = "https://cspxp.pc.ehuatai.com";
|
|
|
- private static final String REFERER_START_PROCESS = ORIGIN + "/htcsp/VehicleInfoEntryAction.do?cmd=startProcess";
|
|
|
- private static final String REFERER_SAVE_ONE_STEP = ORIGIN + "/htcsp/VehicleInfoEntryAction.do?cmd=saveOneStept";
|
|
|
- private static final String REFERER_QUOTATION_LIST = ORIGIN + "/htcsp/QuotationQueryAction.do?cmd=quotationListAll";
|
|
|
- private static final String REFERER_DOCUMENT_PRINT = ORIGIN + "/htcsp/DocumentPrintAction.do?cmd=queryDocumentPrintList";
|
|
|
- private static final String REFERER_CHECK_INS = ORIGIN + "/htcsp/checkInsAction.do?cmd=welcome&recommendNo=&checkedThreeWriteFlagRecommend=Y";
|
|
|
private static final String CONTENT_TYPE_FORM = "application/x-www-form-urlencoded; charset=UTF-8";
|
|
|
- private static final String CONTENT_TYPE_FORM_SIMPLE = "application/x-www-form-urlencoded";
|
|
|
- private static final String X_REQUESTED_WITH = "XMLHttpRequest";
|
|
|
+ private static final String XHR = "XMLHttpRequest";
|
|
|
private static final String BASE_URL = "https://cspxp.pc.ehuatai.com";
|
|
|
private static final int MAX_RETRIES = 3;
|
|
|
private static final long RETRY_DELAY_MS = 3000;
|
|
|
- private static final long SHORT_RETRY_DELAY_MS = 100;
|
|
|
+ private static final long SHORT_DELAY_MS = 100;
|
|
|
private static final String RISK_CODE = "1251";
|
|
|
private static final String XBCOM_CODE = "927";
|
|
|
private static final String SPECIAL_ACCOUNT_XN = "XN92709001";
|
|
|
- private static final String ERROR_PREFIX = "报价失败:";
|
|
|
+ private static final String ERR_PREFIX = "报价失败:";
|
|
|
private static final String CHINA = "中国";
|
|
|
- private static final String END_DATE_PATTERN = "终保日期\\s*([^;]+)";
|
|
|
- private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
|
|
- private static final String DATE_FORMAT_T = "yyyy-MM-dd'T'HH:mm:ss";
|
|
|
- private static final String PROXY_HOST = "39.98.41.104";
|
|
|
- private static final int PROXY_PORT = 2025;
|
|
|
-
|
|
|
- // ====================== 预编译正则 ======================
|
|
|
- private static final Pattern PATTERN_QUOTATION_NO_NORMAL = Pattern.compile("value=\"(.*?)\"value=\"\" id=\"quotationNo\"");
|
|
|
- private static final Pattern PATTERN_QUOTATION_NO_SPECIAL = Pattern.compile("name=\"quotationNo\" value=\"(.*?)\"");
|
|
|
- private static final Pattern PATTERN_MEAL_ID = Pattern.compile("\"mealid\":\"(.*?)\"");
|
|
|
- private static final Pattern PATTERN_END_DATE = Pattern.compile(END_DATE_PATTERN);
|
|
|
-
|
|
|
- // ====================== 特殊账号列表 ======================
|
|
|
+ private static final String DATE_FMT = "yyyy-MM-dd HH:mm:ss";
|
|
|
+ private static final String DATE_FMT_T = "yyyy-MM-dd'T'HH:mm:ss";
|
|
|
+
|
|
|
+ private static final Pattern PAT_QNO_NORMAL = Pattern.compile("value=\"(.*?)\"value=\"\" id=\"quotationNo\"");
|
|
|
+ private static final Pattern PAT_QNO_SPECIAL = Pattern.compile("name=\"quotationNo\" value=\"(.*?)\"");
|
|
|
+ private static final Pattern PAT_MEAL_ID = Pattern.compile("\"mealid\":\"(.*?)\"");
|
|
|
+ private static final Pattern LIMIT_AMOUNT = Pattern.compile("value=\"(.*?)\" id=\"js_actualvalue\"");
|
|
|
+ private static final Pattern PAT_END_DATE = Pattern.compile("终保日期\\s*([^;]+)");
|
|
|
+
|
|
|
private static final Set<String> SPECIAL_USERS = Set.of(
|
|
|
"EA27000180", "EA27000401", "EA27000098", "EA27000076",
|
|
|
"EA27000385", "EA27000336", "EA27000393", "EA27000182",
|
|
|
"EA27000381", "EA27000394", "XN9279003"
|
|
|
);
|
|
|
|
|
|
- // ====================== 依赖注入 ======================
|
|
|
- private final HuaTaiCrawlerCacheComponent huaTaiCrawlerCacheComponent;
|
|
|
- private final HtCrawlerRequestComponent htCrawlerRequestComponent;
|
|
|
- private final HuaTaiCrawlerProperties huaTaiCrawlerProperties;
|
|
|
- private final HtCrawlerOrderService htCrawlerOrderService;
|
|
|
+ // ====================== 依赖 ======================
|
|
|
+ private final HuaTaiCrawlerCacheComponent cache;
|
|
|
+ private final HtCrawlerRequestComponent req;
|
|
|
+ private final HuaTaiCrawlerProperties props;
|
|
|
+ private final HtCrawlerOrderService orderService;
|
|
|
private final PlatformClient platformClient;
|
|
|
- private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
|
|
-
|
|
|
- // ====================== 单例 RestTemplate ======================
|
|
|
- private static final RestTemplate REST_TEMPLATE = createRestTemplate();
|
|
|
+ private static final ObjectMapper MAPPER = new ObjectMapper();
|
|
|
+ private static final RestTemplate RT = createRestTemplate();
|
|
|
|
|
|
private static RestTemplate createRestTemplate() {
|
|
|
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory() {
|
|
|
@Override
|
|
|
- protected void prepareConnection(@NotNull HttpURLConnection connection, @NotNull String httpMethod) throws IOException {
|
|
|
- if (connection instanceof HttpsURLConnection) {
|
|
|
- try {
|
|
|
- TrustManager[] trustAllCerts = new TrustManager[]{
|
|
|
- new X509TrustManager() {
|
|
|
- @Override
|
|
|
- public X509Certificate[] getAcceptedIssuers() {
|
|
|
- return new X509Certificate[0];
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void checkClientTrusted(X509Certificate[] certs, String authType) {
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void checkServerTrusted(X509Certificate[] certs, String authType) {
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
- SSLContext sslContext = SSLContext.getInstance("TLS");
|
|
|
- sslContext.init(null, trustAllCerts, new SecureRandom());
|
|
|
- ((HttpsURLConnection) connection).setSSLSocketFactory(sslContext.getSocketFactory());
|
|
|
- ((HttpsURLConnection) connection).setHostnameVerifier((hostname, session) -> true);
|
|
|
- } catch (Exception e) {
|
|
|
- throw new RuntimeException(e);
|
|
|
- }
|
|
|
- }
|
|
|
- super.prepareConnection(connection, httpMethod);
|
|
|
+ protected void prepareConnection(@NotNull HttpURLConnection c, @NotNull String m) throws IOException {
|
|
|
+ if (c instanceof HttpsURLConnection) trustAll((HttpsURLConnection) c);
|
|
|
+ super.prepareConnection(c, m);
|
|
|
}
|
|
|
};
|
|
|
- Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(PROXY_HOST, PROXY_PORT));
|
|
|
- factory.setProxy(proxy);
|
|
|
+ factory.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("39.98.41.104", 2025)));
|
|
|
return new RestTemplate(factory);
|
|
|
}
|
|
|
|
|
|
- private static RestTemplate getRestTemplate() {
|
|
|
- return REST_TEMPLATE;
|
|
|
- }
|
|
|
-
|
|
|
- // ====================== 登录相关 ======================
|
|
|
-
|
|
|
- @Override
|
|
|
- public void login(LoginBase loginBase) {
|
|
|
- // 空实现
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public GetCaptchaResponse getCaptcha(GetCaptchaRequest sendCaptchaRequest) {
|
|
|
- return null;
|
|
|
- }
|
|
|
+ private static void trustAll(HttpsURLConnection c) {
|
|
|
+ try {
|
|
|
+ TrustManager[] tm = {new X509TrustManager() {
|
|
|
+ public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
|
|
|
+ public void checkClientTrusted(X509Certificate[] certs, String authType) { }
|
|
|
+ public void checkServerTrusted(X509Certificate[] certs, String authType) { }
|
|
|
+ }};
|
|
|
+ SSLContext ctx = SSLContext.getInstance("TLS");
|
|
|
+ ctx.init(null, tm, new SecureRandom());
|
|
|
+ c.setSSLSocketFactory(ctx.getSocketFactory());
|
|
|
+ c.setHostnameVerifier((h, s) -> true);
|
|
|
+ } catch (Exception e) { throw new RuntimeException(e); }
|
|
|
+ }
|
|
|
+
|
|
|
+ // ====================== 登录 ======================
|
|
|
+ @Override public void login(LoginBase loginBase) { }
|
|
|
+ @Override public GetCaptchaResponse getCaptcha(GetCaptchaRequest r) { return null; }
|
|
|
|
|
|
@Override
|
|
|
- public boolean detectLogin(DetectLoginRequest detectLoginRequest) {
|
|
|
- String cookie = htCrawlerRequestComponent.getCookie();
|
|
|
+ public boolean detectLogin(DetectLoginRequest r) {
|
|
|
+ String cookie = req.getCookie();
|
|
|
if (!StringUtils.hasText(cookie)) {
|
|
|
- cookie = htCrawlerRequestComponent.getHaTaiCookie(
|
|
|
- RequestUrl.NE_COOKIE.getRequestUrl(huaTaiCrawlerProperties.getBaseUrl()));
|
|
|
+ cookie = req.getHaTaiCookie(RequestUrl.NE_COOKIE.getRequestUrl(props.getBaseUrl()));
|
|
|
}
|
|
|
return StringUtils.hasText(cookie);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public Map<String, Object> login(LoginDTO loginDTO) {
|
|
|
- return htCrawlerRequestComponent.authenticate(loginDTO, HtRequestConstant.REQUEST_NUMBER);
|
|
|
+ public Map<String, Object> login(LoginDTO dto) {
|
|
|
+ return req.authenticate(dto, HtRequestConstant.REQUEST_NUMBER);
|
|
|
}
|
|
|
|
|
|
// ====================== 重试工具 ======================
|
|
|
-
|
|
|
@FunctionalInterface
|
|
|
- public interface RetryableTask<T> {
|
|
|
- T execute() throws Exception;
|
|
|
- }
|
|
|
-
|
|
|
- private <T> T executeWithRetry(RetryableTask<T> task, int maxRetries, long delayMs, String taskName) {
|
|
|
- int retryCount = 0;
|
|
|
- while (retryCount < maxRetries) {
|
|
|
- try {
|
|
|
- return task.execute();
|
|
|
- } catch (Exception e) {
|
|
|
- retryCount++;
|
|
|
- log.warn("{} 失败,第 {} 次重试", taskName, retryCount);
|
|
|
- if (retryCount >= maxRetries) {
|
|
|
- throw new SystemException(taskName + " 失败,已重试 " + maxRetries + " 次", e.getMessage());
|
|
|
- }
|
|
|
- sleepQuietly(delayMs);
|
|
|
+ public interface RetryableTask<T> { T execute() throws Exception; }
|
|
|
+
|
|
|
+ private <T> T retry(RetryableTask<T> task, int max, long delay, String name) {
|
|
|
+ for (int i = 0; i < max; i++) {
|
|
|
+ try { return task.execute(); }
|
|
|
+ catch (Exception e) {
|
|
|
+ log.warn("{} 失败,第 {} 次重试", name, i + 1);
|
|
|
+ if (i + 1 >= max) throw new SystemException(name + " 失败,已重试 " + max + " 次", e.getMessage());
|
|
|
+ sleep(delay);
|
|
|
}
|
|
|
}
|
|
|
- throw new SystemException(taskName + " 失败,已达到最大重试次数");
|
|
|
+ throw new SystemException(name + " 失败,已达到最大重试次数");
|
|
|
}
|
|
|
|
|
|
- private void sleepQuietly(long millis) {
|
|
|
- try {
|
|
|
- Thread.sleep(millis);
|
|
|
- } catch (InterruptedException ie) {
|
|
|
- Thread.currentThread().interrupt();
|
|
|
- throw new RuntimeException("重试被中断", ie);
|
|
|
- }
|
|
|
+ private void sleep(long ms) {
|
|
|
+ try { Thread.sleep(ms); }
|
|
|
+ catch (InterruptedException ie) { Thread.currentThread().interrupt(); throw new RuntimeException("重试被中断", ie); }
|
|
|
}
|
|
|
|
|
|
// ====================== 续保查询 ======================
|
|
|
-
|
|
|
- public Map<String, Object> xbQuery(String username, String cookie, CarInfoVo carInfoVo) throws Exception {
|
|
|
+ public Map<String, Object> xbQuery(String username, String cookie, CarInfoVo car) throws Exception {
|
|
|
log.info("开始续保查询");
|
|
|
- String modelcodexh = "";
|
|
|
- String quotationNo = "";
|
|
|
- HttpHeaders headers = buildHtmlHeadersWithCookie(cookie);
|
|
|
- headers.set("Referer", "https://cspxp.pc.ehuatai.com/htcsp/ShakeHandsAction.do?cmd=menuControl&ip=172.16.100.27&host=9000&menuCode=car_001&messageClickType=&mesFlag=");
|
|
|
-
|
|
|
- boolean isSpecial = SPECIAL_USERS.contains(username) || SPECIAL_ACCOUNT_XN.equals(username);
|
|
|
-
|
|
|
- if (isSpecial) {
|
|
|
- headers = buildSpecialHeaders(cookie);
|
|
|
- HttpEntity<String> entity = new HttpEntity<>(headers);
|
|
|
- getRestTemplate().exchange(
|
|
|
- huaTaiCrawlerProperties.getBaseUrl() + "/htcsp/ShakeHandsAction.do?cmd=menuControl&ip=172.16.100.27&host=9000&menuCode=car_001&messageClickType=&mesFlag=",
|
|
|
- HttpMethod.POST, entity, String.class);
|
|
|
- log.info("xbQuery:menuControl");
|
|
|
- headers = buildSpecialHeaders2(cookie);
|
|
|
- }
|
|
|
+ boolean special = SPECIAL_USERS.contains(username) || SPECIAL_ACCOUNT_XN.equals(username);
|
|
|
|
|
|
- HttpEntity<String> getEntity = new HttpEntity<>(headers);
|
|
|
- ResponseEntity<String> respStart = getRestTemplate().exchange(
|
|
|
- huaTaiCrawlerProperties.getBaseUrl() + "/htcsp/VehicleInfoEntryAction.do?cmd=startProcess",
|
|
|
- HttpMethod.GET, getEntity, String.class);
|
|
|
- log.info("xbQuery:startProcess");
|
|
|
+ HttpHeaders headers = special ? buildSpecialHeaders(cookie, true) : buildHtmlHeaders(cookie);
|
|
|
+ if (special) {
|
|
|
+ get(ORIGIN + "/htcsp/ShakeHandsAction.do?cmd=menuControl&ip=172.16.100.27&host=9000&menuCode=car_001&messageClickType=&mesFlag=", headers, null);
|
|
|
+ headers = buildSpecialHeaders(cookie, false);
|
|
|
+ }
|
|
|
|
|
|
- quotationNo = extractQuotationNo(respStart.getBody(), isSpecial);
|
|
|
+ String body = get(props.getBaseUrl() + "/htcsp/VehicleInfoEntryAction.do?cmd=startProcess", headers, null);
|
|
|
+ String quotationNo = extractQuotationNo(body, special);
|
|
|
log.info("quotationNo: {}", quotationNo);
|
|
|
|
|
|
- headers = buildJsonHeadersWithCookie(cookie);
|
|
|
- Map<String, Object> dataMap = buildXbQueryDataMap(carInfoVo, quotationNo);
|
|
|
+ Map<String, Object> dataMap = buildXbQueryMap(car, quotationNo);
|
|
|
Map<String, Object> encrypted = encrypt(dataMap);
|
|
|
- log.info("xbQuery:encrypted: {}", encrypted);
|
|
|
-
|
|
|
- MultiValueMap<String, String> postData = buildEncryptedPostData(encrypted);
|
|
|
- HttpEntity<MultiValueMap<String, String>> postEntity = new HttpEntity<>(postData, headers);
|
|
|
- ResponseEntity<String> respXbquery = getRestTemplate().exchange(
|
|
|
- huaTaiCrawlerProperties.getBaseUrl() + "/htcsp/VehicleInfoEntryAction.do?cmd=xbquery",
|
|
|
- HttpMethod.POST, postEntity, String.class);
|
|
|
- log.info("xbQuery:xbquery:response");
|
|
|
-
|
|
|
- Map<String, Object> res = decrypt(OBJECT_MAPPER.readValue(respXbquery.getBody(), HashMap.class));
|
|
|
- log.info("xbQuery:xbquery: {}", JSONObject.toJSONString(res));
|
|
|
-
|
|
|
- Map<String, Object> carmodeldtojson = (Map<String, Object>) res.get("carmodeldtojson");
|
|
|
- if (carmodeldtojson != null && !carmodeldtojson.isEmpty()) {
|
|
|
- modelcodexh = (String) carmodeldtojson.get("modelcodexh");
|
|
|
- log.info("modelcodexh: {}", modelcodexh);
|
|
|
- }
|
|
|
+ log.info("xbQuery encrypted: {}", encrypted);
|
|
|
|
|
|
- Map<String, Object> result = new HashMap<>();
|
|
|
- result.put("quotationNo", quotationNo);
|
|
|
- result.put("modelcodexh", modelcodexh);
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
- private String extractQuotationNo(String body, boolean isSpecial) {
|
|
|
- Pattern pattern = isSpecial ? PATTERN_QUOTATION_NO_SPECIAL : PATTERN_QUOTATION_NO_NORMAL;
|
|
|
- Matcher matcher = pattern.matcher(body);
|
|
|
- return matcher.find() ? matcher.group(1) : "";
|
|
|
- }
|
|
|
-
|
|
|
- private Map<String, Object> buildXbQueryDataMap(CarInfoVo carInfoVo, String quotationNo) {
|
|
|
- Map<String, Object> dataMap = new HashMap<>();
|
|
|
- dataMap.put("licenseplateno", carInfoVo.getLicenseNo());
|
|
|
- dataMap.put("vin", carInfoVo.getVinNo());
|
|
|
- dataMap.put("engineno", carInfoVo.getEngineNo());
|
|
|
- dataMap.put("liceenseplatetype", carInfoVo.getLicenseKindCode());
|
|
|
- dataMap.put("ecdemicvehicleflag", "0");
|
|
|
- fillVehicleTypeCodes(carInfoVo, dataMap);
|
|
|
- dataMap.put("xbcomcode", XBCOM_CODE);
|
|
|
- dataMap.put("quotationNo", quotationNo);
|
|
|
- dataMap.put("riskCode", RISK_CODE);
|
|
|
- dataMap.put("engineno2", "");
|
|
|
- dataMap.put("enrollDate", "");
|
|
|
- dataMap.put("isJllxFlagType", "1");
|
|
|
- dataMap.put("carModelCodexhQuery", "1");
|
|
|
- dataMap.put("telemarketFlag", "");
|
|
|
- return dataMap;
|
|
|
- }
|
|
|
-
|
|
|
- private MultiValueMap<String, String> buildEncryptedPostData(Map<String, Object> encrypted) {
|
|
|
MultiValueMap<String, String> postData = new LinkedMultiValueMap<>();
|
|
|
postData.add("sourceCode", String.valueOf(encrypted.get("sourceCode")));
|
|
|
postData.add("accessToken", (String) encrypted.get("accessToken"));
|
|
|
postData.add("data", (String) encrypted.get("data"));
|
|
|
postData.add("insuredCode", "");
|
|
|
- return postData;
|
|
|
+
|
|
|
+ Map<String, Object> res = decrypt(MAPPER.readValue(
|
|
|
+ post(props.getBaseUrl() + "/htcsp/VehicleInfoEntryAction.do?cmd=xbquery", buildJsonHeaders(cookie), postData),
|
|
|
+ HashMap.class));
|
|
|
+ log.info("xbQuery result: {}", JSONObject.toJSONString(res));
|
|
|
+
|
|
|
+ Map<String, Object> carmodel = (Map<String, Object>) res.get("carmodeldtojson");
|
|
|
+ String modelcodexh = carmodel != null ? (String) carmodel.get("modelcodexh") : "";
|
|
|
+ log.info("modelcodexh: {}", modelcodexh);
|
|
|
+
|
|
|
+ return Map.of("quotationNo", quotationNo, "modelcodexh", modelcodexh);
|
|
|
}
|
|
|
|
|
|
- // ====================== 报价主流程 ======================
|
|
|
+ private String extractQuotationNo(String body, boolean special) {
|
|
|
+ Matcher m = (special ? PAT_QNO_SPECIAL : PAT_QNO_NORMAL).matcher(body);
|
|
|
+ return m.find() ? m.group(1) : "";
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, Object> buildXbQueryMap(CarInfoVo car, String quotationNo) {
|
|
|
+ Map<String, Object> m = new HashMap<>();
|
|
|
+ m.put("licenseplateno", car.getLicenseNo());
|
|
|
+ m.put("vin", car.getVinNo());
|
|
|
+ m.put("engineno", car.getEngineNo());
|
|
|
+ m.put("liceenseplatetype", car.getLicenseKindCode());
|
|
|
+ m.put("ecdemicvehicleflag", "0");
|
|
|
+ fillVehicleTypeCodes(car, m);
|
|
|
+ m.put("xbcomcode", XBCOM_CODE);
|
|
|
+ m.put("quotationNo", quotationNo);
|
|
|
+ m.put("riskCode", RISK_CODE);
|
|
|
+ m.putAll(Map.of("engineno2", "", "enrollDate", "", "isJllxFlagType", "1",
|
|
|
+ "carModelCodexhQuery", "1", "telemarketFlag", ""));
|
|
|
+ return m;
|
|
|
+ }
|
|
|
|
|
|
+ // ====================== 报价主流程 ======================
|
|
|
@Override
|
|
|
public QuoteResultsVo quote(QuoteVo quoteVo) throws Exception {
|
|
|
- AttributionInformationVo attributionInformationVo = quoteVo.getOrder().getAttributionInformationVo();
|
|
|
- LoginDTO loginDTO = buildLoginDTO(attributionInformationVo);
|
|
|
- Map<String, Object> mmap = login(loginDTO);
|
|
|
+ AttributionInformationVo attr = quoteVo.getOrder().getAttributionInformationVo();
|
|
|
+ LoginDTO dto = buildLoginDTO(attr);
|
|
|
+ Map<String, Object> mmap = login(dto);
|
|
|
+ //归属信息
|
|
|
Map<String, Object> gsInfo = parseToMap(mmap.get("gsInfo").toString());
|
|
|
log.info("gsInfo: {}", JSONObject.toJSONString(mmap));
|
|
|
|
|
|
String cookie = extractCookie(mmap);
|
|
|
- CarInfoVo carInfoVo = quoteVo.getCarInfoVo();
|
|
|
-
|
|
|
- // 预报价(带重试)
|
|
|
- Map<String, Object> xbResult = executeXbQueryWithRetry(loginDTO, cookie, carInfoVo);
|
|
|
- String quotationNo = getStringValue(xbResult, "quotationNo");
|
|
|
- String modelcodexh = getStringValue(xbResult, "modelcodexh");
|
|
|
-
|
|
|
- // 报价前预处理
|
|
|
- QuotePreResult preResult = prepareQuote(attributionInformationVo, mmap, carInfoVo, modelcodexh, cookie, quotationNo);
|
|
|
+ CarInfoVo car = quoteVo.getCarInfoVo();
|
|
|
|
|
|
- // 报价核心流程(带重试)
|
|
|
- QuoteCoreResult coreResult = executeQuoteWithRetry(quoteVo, quotationNo, loginDTO, cookie, preResult, gsInfo, attributionInformationVo);
|
|
|
-
|
|
|
- if (!coreResult.success()) {
|
|
|
- throw new RuntimeException("报价失败,已达到最大重试次数");
|
|
|
- }
|
|
|
-
|
|
|
- // 保存订单
|
|
|
- saveCrawlerOrder(quoteVo, coreResult);
|
|
|
-
|
|
|
- return HuaTaiCrawlerQuoteResultsVoBuild.buildQuoteResultsVo(quoteVo, coreResult.quoteResponseData(), coreResult.fcPrice());
|
|
|
- }
|
|
|
+ //带重试的获取报价编号、车型型号
|
|
|
+ Map<String, Object> xbResult = retry(() -> {
|
|
|
+ try { return xbQuery(dto.getUsername(), cookie, car); }
|
|
|
+ catch (Exception e) { refreshLogin(dto); throw e; }
|
|
|
+ }, MAX_RETRIES, RETRY_DELAY_MS, "预报价获取登录信息");
|
|
|
|
|
|
- private LoginDTO buildLoginDTO(AttributionInformationVo attributionInformationVo) {
|
|
|
- LoginDTO loginDTO = new LoginDTO();
|
|
|
- Map<String, String> configInfo = attributionInformationVo.getConfigInfo();
|
|
|
- loginDTO.setComcode(configInfo.get("comCode"));
|
|
|
- loginDTO.setUsername(attributionInformationVo.getUsername());
|
|
|
- loginDTO.setPassword(attributionInformationVo.getPassword());
|
|
|
- loginDTO.setUseridname(configInfo.get("userid_name"));
|
|
|
- loginDTO.setDlrCode(configInfo.get("dlr_code"));
|
|
|
- loginDTO.setDlxyCode(configInfo.get("dlxy_code"));
|
|
|
- return loginDTO;
|
|
|
+ String quotationNo = str(xbResult, "quotationNo");
|
|
|
+ String modelcodexh = str(xbResult, "modelcodexh");
|
|
|
+ //报价前预处理-保存车辆信息、过滤车型等处理
|
|
|
+ PreResult pre = prepareQuote(attr, mmap, car, modelcodexh, cookie, quotationNo);
|
|
|
+ //带重试的报价
|
|
|
+ CoreResult core = executeQuoteWithRetry(quoteVo, quotationNo, dto, cookie, pre, gsInfo, attr);
|
|
|
+
|
|
|
+ if (!core.success()) throw new RuntimeException("报价失败,已达到最大重试次数");
|
|
|
+ //保存订单到MongoDB
|
|
|
+ saveOrder(quoteVo, core);
|
|
|
+ //组装费用
|
|
|
+ return HuaTaiCrawlerQuoteResultsVoBuild.buildQuoteResultsVo(quoteVo, core.data(), core.fcPrice());
|
|
|
+ }
|
|
|
+
|
|
|
+ private LoginDTO buildLoginDTO(AttributionInformationVo attr) {
|
|
|
+ Map<String, String> cfg = attr.getConfigInfo();
|
|
|
+ LoginDTO dto = new LoginDTO();
|
|
|
+ dto.setComcode(cfg.get("comCode"));
|
|
|
+ dto.setUsername(attr.getUsername());
|
|
|
+ dto.setPassword(attr.getPassword());
|
|
|
+ dto.setUseridname(cfg.get("userid_name"));
|
|
|
+ //代理人
|
|
|
+ dto.setDlrCode(cfg.get("dlr_code"));
|
|
|
+ //代理协议
|
|
|
+ dto.setDlxyCode(cfg.get("dlxy_code"));
|
|
|
+ return dto;
|
|
|
}
|
|
|
|
|
|
private String extractCookie(Map<String, Object> mmap) {
|
|
|
- try {
|
|
|
- String cookies = (String) mmap.get("cookies");
|
|
|
- return StringUtils.isBlank(cookies) ? "" : cookies;
|
|
|
- } catch (Exception e) {
|
|
|
- throw new SystemException("获取必要信息失败,请稍后重试");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private Map<String, Object> executeXbQueryWithRetry(LoginDTO loginDTO, String cookie, CarInfoVo carInfoVo) {
|
|
|
- return executeWithRetry(() -> {
|
|
|
- try {
|
|
|
- return xbQuery(loginDTO.getUsername(), cookie, carInfoVo);
|
|
|
- } catch (Exception e) {
|
|
|
- refreshLogin(loginDTO);
|
|
|
- throw e;
|
|
|
- }
|
|
|
- }, MAX_RETRIES, RETRY_DELAY_MS, "预报价获取登录信息");
|
|
|
+ String cookies = (String) mmap.get("cookies");
|
|
|
+ return StringUtils.isBlank(cookies) ? "" : cookies;
|
|
|
}
|
|
|
|
|
|
- private void refreshLogin(LoginDTO loginDTO) {
|
|
|
- huaTaiCrawlerCacheComponent.cacheCookie("");
|
|
|
- huaTaiCrawlerCacheComponent.cacheGsInfo("");
|
|
|
- huaTaiCrawlerCacheComponent.cacheComCode("");
|
|
|
- Map<String, Object> mmap = login(loginDTO);
|
|
|
- log.info("refreshLogin gsInfo: {}", JSONObject.toJSONString(mmap));
|
|
|
+ private void refreshLogin(LoginDTO dto) {
|
|
|
+ cache.cacheCookie("");
|
|
|
+ cache.cacheGsInfo("");
|
|
|
+ cache.cacheComCode("");
|
|
|
+ log.info("refreshLogin gsInfo: {}", JSONObject.toJSONString(login(dto)));
|
|
|
}
|
|
|
|
|
|
- private String getStringValue(Map<String, Object> map, String key) {
|
|
|
- Object value = map.get(key);
|
|
|
- return value == null ? "" : value.toString();
|
|
|
- }
|
|
|
-
|
|
|
- // ====================== 内部记录类 ======================
|
|
|
-
|
|
|
- private record QuotePreResult(HtCrawlerConfigureParameters parameters,
|
|
|
- HtCrawlerCarQueryResponse.DataDTO dataDTO,
|
|
|
- HtCrawlerCarQueryResponse.DataDTO.DataListDTO carDTO) {
|
|
|
+ private String str(Map<String, Object> m, String k) {
|
|
|
+ Object v = m.get(k);
|
|
|
+ return v == null ? "" : v.toString();
|
|
|
}
|
|
|
|
|
|
- private record QuoteCoreResult(String fcPrice,
|
|
|
- HtCrawlerQuoteResponse.DataDTO quoteResponseData,
|
|
|
- boolean success) {
|
|
|
- }
|
|
|
+ // ====================== 内部记录 ======================
|
|
|
+ private record PreResult(HtCrawlerConfigureParameters params,
|
|
|
+ HtCrawlerCarQueryResponse.DataDTO dataDTO,
|
|
|
+ HtCrawlerCarQueryResponse.DataDTO.DataListDTO carDTO) { }
|
|
|
|
|
|
- private record QuoteStepResult(HtCrawlerQuoteResponse.DataDTO quoteResponseData, String personalInsuredJSONString) {
|
|
|
- }
|
|
|
+ private record CoreResult(String fcPrice, HtCrawlerQuoteResponse.DataDTO data, boolean success) { }
|
|
|
|
|
|
- // ====================== 私有辅助方法 ======================
|
|
|
+ private record StepResult(HtCrawlerQuoteResponse.DataDTO data, String personalInsuredJSON) { }
|
|
|
|
|
|
- private void saveCrawlerOrder(QuoteVo quoteVo, QuoteCoreResult coreResult) {
|
|
|
- HtCrawlerOrder htCrawlerOrder = new HtCrawlerOrder();
|
|
|
- htCrawlerOrder.setOrdersNo(quoteVo.getOrder().getOrdersNo());
|
|
|
- String ciCategory = coreResult.quoteResponseData().getApplicationdto().getCicategory();
|
|
|
- htCrawlerOrder.setCiCategory(ciCategory);
|
|
|
- String biCategory = coreResult.quoteResponseData().getApplicationdto().getBicategory();
|
|
|
- htCrawlerOrder.setBiCategory(biCategory);
|
|
|
- htCrawlerOrder.setQuotationRelaNo(coreResult.quoteResponseData().getQuotationRelaNo());
|
|
|
- htCrawlerOrderService.save(htCrawlerOrder);
|
|
|
+ private void saveOrder(QuoteVo q, CoreResult c) {
|
|
|
+ HtCrawlerOrder o = new HtCrawlerOrder();
|
|
|
+ o.setOrdersNo(q.getOrder().getOrdersNo());
|
|
|
+ o.setCiCategory(c.data().getApplicationdto().getCicategory());
|
|
|
+ o.setBiCategory(c.data().getApplicationdto().getBicategory());
|
|
|
+ o.setQuotationRelaNo(c.data().getQuotationRelaNo());
|
|
|
+ orderService.save(o);
|
|
|
}
|
|
|
|
|
|
// ====================== 报价预处理 ======================
|
|
|
-
|
|
|
- private QuotePreResult prepareQuote(AttributionInformationVo attributionInformationVo, Map<String, Object> mmap,
|
|
|
- CarInfoVo carInfoVo, String modelcodexh, String cookie, String quotationNo) throws JsonProcessingException {
|
|
|
- HtCrawlerConfigureParameters parameters = ConfigureParametersConversion.conversionEntity(
|
|
|
- HtCrawlerConfigureParameters.class, attributionInformationVo.getConfigInfo());
|
|
|
- parameters.setFullComCode(mmap.get("comCode").toString());
|
|
|
-
|
|
|
- HttpHeaders headers = htCrawlerRequestComponent.getHeaders1();
|
|
|
- carInfoVo.setPurchasePrice(carInfoVo.getPurchasePrice().replace(".00", ""));
|
|
|
-
|
|
|
- HtCrawlerCarQueryRequest carQueryRequest = new HtCrawlerCarQueryRequest(carInfoVo, modelcodexh);
|
|
|
- HtCrawlerCarQueryResponse.DataDTO dataDTO;
|
|
|
- try {
|
|
|
- dataDTO = htCrawlerRequestComponent.carQuery(carQueryRequest, headers, carInfoVo);
|
|
|
- } catch (Exception e) {
|
|
|
- throw new SystemException(e.getMessage());
|
|
|
- }
|
|
|
-
|
|
|
- HtCrawlerCarQueryResponse.DataDTO.DataListDTO carDTO = CarModelsFilterUtils.to(dataDTO.getDatalist(), carInfoVo);
|
|
|
-
|
|
|
- // savecarquery
|
|
|
- executeSaveCarQuery(carDTO, dataDTO, carInfoVo, cookie);
|
|
|
-
|
|
|
- // carModelCodexhQuery
|
|
|
- executeCarModelCodexhQuery(carDTO, carInfoVo, cookie, quotationNo);
|
|
|
-
|
|
|
- // messageCentreTimeBoom
|
|
|
+ private PreResult prepareQuote(AttributionInformationVo attr, Map<String, Object> mmap,
|
|
|
+ CarInfoVo car, String modelcodexh, String cookie, String quotationNo) throws Exception {
|
|
|
+ HtCrawlerConfigureParameters params = ConfigureParametersConversion.conversionEntity(
|
|
|
+ HtCrawlerConfigureParameters.class, attr.getConfigInfo());
|
|
|
+ params.setFullComCode(mmap.get("comCode").toString());
|
|
|
+ //参数格式保持一致
|
|
|
+ car.setPurchasePrice(car.getPurchasePrice().replace(".00", ""));
|
|
|
+ //车辆查询
|
|
|
+ HtCrawlerCarQueryResponse.DataDTO dataDTO = req.carQuery(
|
|
|
+ new HtCrawlerCarQueryRequest(car, modelcodexh), req.getHeaders1(), car);
|
|
|
+ //过滤车型
|
|
|
+ HtCrawlerCarQueryResponse.DataDTO.DataListDTO carDTO = CarModelsFilterUtils.to(dataDTO.getDatalist(), car);
|
|
|
+ //保存车辆信息
|
|
|
+ executeSaveCarQuery(carDTO, dataDTO, car, cookie);
|
|
|
+ //车型查询
|
|
|
+ executeCarModelCodexhQuery(carDTO, car, cookie, quotationNo);
|
|
|
+ //额外请求
|
|
|
executeMessageCentreTimeBoom(cookie);
|
|
|
-
|
|
|
- return new QuotePreResult(parameters, dataDTO, carDTO);
|
|
|
+ //以上请求模拟浏览器请求流程,否则报价失败
|
|
|
+ return new PreResult(params, dataDTO, carDTO);
|
|
|
}
|
|
|
|
|
|
private void executeSaveCarQuery(HtCrawlerCarQueryResponse.DataDTO.DataListDTO carDTO,
|
|
|
- HtCrawlerCarQueryResponse.DataDTO dataDTO, CarInfoVo carInfoVo, String cookie) throws JsonProcessingException {
|
|
|
- String aa = OBJECT_MAPPER.writeValueAsString(carDTO);
|
|
|
- String encodedAa = URLEncoder.encode(aa, StandardCharsets.UTF_8);
|
|
|
- String bb = OBJECT_MAPPER.writeValueAsString(dataDTO.getDatalist2().get(0));
|
|
|
- String encodedBb = URLEncoder.encode(bb, StandardCharsets.UTF_8);
|
|
|
-
|
|
|
- HttpHeaders headers = buildCarQueryHeaders(cookie);
|
|
|
- MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
|
|
|
- formData.add("carmodelStr", encodedAa);
|
|
|
- formData.add("commonoutputStr", encodedBb);
|
|
|
- formData.add("transcodeStr", dataDTO.getTranscodeStr());
|
|
|
- formData.add("pmquerynoStr", "");
|
|
|
- formData.add("vin", carInfoVo.getVinNo());
|
|
|
- formData.add("modelcodexh", carDTO.getModelcodexh());
|
|
|
- formData.add("VehicleStyleUniqueId", "");
|
|
|
-
|
|
|
- HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
|
|
|
- getRestTemplate().postForEntity(
|
|
|
- BASE_URL + "/htcsp/VehicleInfoEntryAction.do?cmd=savecarquery",
|
|
|
- requestEntity, String.class);
|
|
|
+ HtCrawlerCarQueryResponse.DataDTO dataDTO, CarInfoVo car, String cookie) throws JsonProcessingException {
|
|
|
+ String aa = URLEncoder.encode(MAPPER.writeValueAsString(carDTO), StandardCharsets.UTF_8);
|
|
|
+ String bb = URLEncoder.encode(MAPPER.writeValueAsString(dataDTO.getDatalist2().get(0)), StandardCharsets.UTF_8);
|
|
|
+
|
|
|
+ MultiValueMap<String, String> fd = new LinkedMultiValueMap<>();
|
|
|
+ fd.add("carmodelStr", aa);
|
|
|
+ fd.add("commonoutputStr", bb);
|
|
|
+ fd.add("transcodeStr", dataDTO.getTranscodeStr());
|
|
|
+ fd.add("pmquerynoStr", "");
|
|
|
+ fd.add("vin", car.getVinNo());
|
|
|
+ fd.add("modelcodexh", carDTO.getModelcodexh());
|
|
|
+ fd.add("VehicleStyleUniqueId", "");
|
|
|
+
|
|
|
+ post(BASE_URL + "/htcsp/VehicleInfoEntryAction.do?cmd=savecarquery", buildCarQueryHeaders(cookie), fd);
|
|
|
}
|
|
|
|
|
|
private void executeCarModelCodexhQuery(HtCrawlerCarQueryResponse.DataDTO.DataListDTO carDTO,
|
|
|
- CarInfoVo carInfoVo, String cookie, String quotationNo) {
|
|
|
- HttpHeaders headers = buildCarModelCodexhHeaders(cookie);
|
|
|
- MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
|
|
|
- formData.add("modelCode", carDTO.getModelcodexh());
|
|
|
- formData.add("licenseNo", carInfoVo.getLicenseNo());
|
|
|
- formData.add("licenseKindCode", "02 小型汽车号牌");
|
|
|
- formData.add("engineNo", carInfoVo.getEngineNo());
|
|
|
- formData.add("frameNo", carInfoVo.getVinNo());
|
|
|
- formData.add("useNatureCode", "8A 家庭自用");
|
|
|
- formData.add("carKindCode", "A0 客车");
|
|
|
- formData.add("enrollDate", carInfoVo.getRegisterDate());
|
|
|
- formData.add("completeKerbMass", "1250");
|
|
|
- formData.add("seatCount", carDTO.getLimitloadperson());
|
|
|
- formData.add("noticeType", carDTO.getNoticetype());
|
|
|
- formData.add("carName", carDTO.getModelname());
|
|
|
- formData.add("purchasePrice", carDTO.getPurchasePrice());
|
|
|
- formData.add("tonCount", carDTO.getLimitload());
|
|
|
- formData.add("exhaustScale", carDTO.getDisplacement());
|
|
|
- formData.add("carModelComCode", XBCOM_CODE);
|
|
|
- formData.add("quotationNo", quotationNo);
|
|
|
-
|
|
|
- HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
|
|
|
- getRestTemplate().postForEntity(
|
|
|
- BASE_URL + "/htcsp/VehicleInfoEntryAction.do?cmd=carModelCodexhQuery",
|
|
|
- requestEntity, String.class);
|
|
|
+ CarInfoVo car, String cookie, String quotationNo) {
|
|
|
+ MultiValueMap<String, String> fd = new LinkedMultiValueMap<>();
|
|
|
+ fd.add("modelCode", carDTO.getModelcodexh());
|
|
|
+ fd.add("licenseNo", car.getLicenseNo());
|
|
|
+ fd.add("licenseKindCode", "02 小型汽车号牌");
|
|
|
+ fd.add("engineNo", car.getEngineNo());
|
|
|
+ fd.add("frameNo", car.getVinNo());
|
|
|
+ fd.add("useNatureCode", "8A 家庭自用");
|
|
|
+ fd.add("carKindCode", "A0 客车");
|
|
|
+ fd.add("enrollDate", car.getRegisterDate());
|
|
|
+ fd.add("completeKerbMass", "1250");
|
|
|
+ fd.add("seatCount", carDTO.getLimitloadperson());
|
|
|
+ fd.add("noticeType", carDTO.getNoticetype());
|
|
|
+ fd.add("carName", carDTO.getModelname());
|
|
|
+ fd.add("purchasePrice", carDTO.getPurchasePrice());
|
|
|
+ fd.add("tonCount", carDTO.getLimitload());
|
|
|
+ fd.add("exhaustScale", carDTO.getDisplacement());
|
|
|
+ fd.add("carModelComCode", XBCOM_CODE);
|
|
|
+ fd.add("quotationNo", quotationNo);
|
|
|
+
|
|
|
+ post(BASE_URL + "/htcsp/VehicleInfoEntryAction.do?cmd=carModelCodexhQuery", buildCarModelCodexhHeaders(cookie), fd);
|
|
|
}
|
|
|
|
|
|
private void executeMessageCentreTimeBoom(String cookie) {
|
|
|
- HttpHeaders headers = new HttpHeaders();
|
|
|
- headers.add("Accept", ACCEPT_ALL);
|
|
|
- headers.add("Content-Type", CONTENT_TYPE_FORM);
|
|
|
- headers.add("User-Agent", USER_AGENT);
|
|
|
- headers.add(HtRequestConstant.COOKIE, cookie);
|
|
|
-
|
|
|
- MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
|
|
|
- formData.add("messageType", "0");
|
|
|
-
|
|
|
- HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
|
|
|
- getRestTemplate().postForEntity(
|
|
|
- BASE_URL + "/htcsp/MessageCentreAction.do?cmd=messageCentreTimeBoom",
|
|
|
- requestEntity, String.class);
|
|
|
+ MultiValueMap<String, String> fd = new LinkedMultiValueMap<>();
|
|
|
+ fd.add("messageType", "0");
|
|
|
+ post(BASE_URL + "/htcsp/MessageCentreAction.do?cmd=messageCentreTimeBoom",
|
|
|
+ header(b -> { b.add(HtRequestConstant.COOKIE, cookie); b.add("Content-Type", CONTENT_TYPE_FORM); }), fd);
|
|
|
}
|
|
|
|
|
|
- // ====================== 报价核心流程 ======================
|
|
|
-
|
|
|
- private QuoteCoreResult executeQuoteWithRetry(QuoteVo quoteVo, String quotationNo, LoginDTO loginDTO,
|
|
|
- String cookie, QuotePreResult preResult,
|
|
|
- Map<String, Object> gsInfo,
|
|
|
- AttributionInformationVo attributionInformationVo) {
|
|
|
- int retryCount = 0;
|
|
|
- boolean success = false;
|
|
|
+ // ====================== 报价核心 ======================
|
|
|
+ private CoreResult executeQuoteWithRetry(QuoteVo quoteVo, String quotationNo, LoginDTO dto,
|
|
|
+ String cookie, PreResult pre,
|
|
|
+ Map<String, Object> gsInfo, AttributionInformationVo attr) {
|
|
|
+ int retry = 0;
|
|
|
String fcPrice = "";
|
|
|
- HtCrawlerQuoteResponse.DataDTO quoteResponseData = null;
|
|
|
+ HtCrawlerQuoteResponse.DataDTO data = null;
|
|
|
|
|
|
- while (retryCount < MAX_RETRIES && !success) {
|
|
|
+ while (retry < MAX_RETRIES) {
|
|
|
try {
|
|
|
- if (retryCount > 0) {
|
|
|
- log.info("第 {} 次重试,重新开始报价流程...", retryCount + 1);
|
|
|
- sleepQuietly(SHORT_RETRY_DELAY_MS);
|
|
|
- }
|
|
|
-
|
|
|
- QuoteStepResult stepResult = executeQuoteSteps(quoteVo, quotationNo, loginDTO, cookie, preResult, gsInfo);
|
|
|
- quoteResponseData = stepResult.quoteResponseData();
|
|
|
+ if (retry > 0) { log.info("第 {} 次重试,重新开始报价流程...", retry + 1); sleep(SHORT_DELAY_MS); }
|
|
|
|
|
|
- if (quoteResponseData.getApplicationdto() != null) {
|
|
|
- success = true;
|
|
|
+ StepResult step = executeQuoteSteps(quoteVo, quotationNo, dto, cookie, pre, gsInfo);
|
|
|
+ data = step.data();
|
|
|
|
|
|
- // 调用非车险保费接口(驾意险)
|
|
|
- if (StringUtils.isNotBlank(stepResult.personalInsuredJSONString())) {
|
|
|
- fcPrice = fetchNoCarPremium(cookie, quotationNo, attributionInformationVo, stepResult.personalInsuredJSONString());
|
|
|
- }
|
|
|
- } else {
|
|
|
- retryCount++;
|
|
|
- log.warn("quoteResponseData.getApplicationdto() 为 null,第 {} 次重试...", retryCount);
|
|
|
- if (retryCount >= MAX_RETRIES) {
|
|
|
- throw new RuntimeException("报价重试次数已达上限,仍然无法获取数据");
|
|
|
+ if (data.getApplicationdto() != null) {
|
|
|
+ if (StringUtils.isNotBlank(step.personalInsuredJSON())) {
|
|
|
+ fcPrice = fetchNoCarPremium(cookie, quotationNo, attr, step.personalInsuredJSON());
|
|
|
}
|
|
|
+ return new CoreResult(fcPrice, data, true);
|
|
|
}
|
|
|
+ log.warn("applicationdto 为 null,第 {} 次重试...", ++retry);
|
|
|
} catch (Exception e) {
|
|
|
- if (e.getMessage() != null && e.getMessage().contains("重试次数已达上限")) {
|
|
|
- throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
|
|
|
- }
|
|
|
- retryCount++;
|
|
|
- log.warn("报价异常,第 {} 次重试... 异常信息: {}", retryCount, e.getMessage());
|
|
|
- if (retryCount >= MAX_RETRIES) {
|
|
|
- throw new RuntimeException("报价重试次数已达上限: " + e.getMessage());
|
|
|
- }
|
|
|
- sleepQuietly(RETRY_DELAY_MS);
|
|
|
+ if (e.getMessage() != null && e.getMessage().contains("重试次数已达上限")) throw wrap(e);
|
|
|
+ log.warn("报价异常,第 {} 次重试... 异常: {}", ++retry, e.getMessage());
|
|
|
+ if (retry >= MAX_RETRIES) throw new RuntimeException("报价重试次数已达上限: " + e.getMessage());
|
|
|
+ sleep(RETRY_DELAY_MS);
|
|
|
}
|
|
|
}
|
|
|
- return new QuoteCoreResult(fcPrice, quoteResponseData, success);
|
|
|
+ return new CoreResult(fcPrice, data, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ private RuntimeException wrap(Exception e) {
|
|
|
+ return e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
|
|
|
}
|
|
|
|
|
|
private String fetchNoCarPremium(String cookie, String quotationNo,
|
|
|
- AttributionInformationVo attributionInformationVo,
|
|
|
- String personalInsuredJSONString) {
|
|
|
+ AttributionInformationVo attr, String personalInsuredJSON) {
|
|
|
try {
|
|
|
- HttpHeaders fcHeaders = buildNoCarPremiumHeaders(cookie);
|
|
|
- MultiValueMap<String, String> fcData = new LinkedMultiValueMap<>();
|
|
|
- fcData.add("noCarProductMes", personalInsuredJSONString);
|
|
|
- fcData.add("quotationNo", quotationNo);
|
|
|
- fcData.add("comCode", attributionInformationVo.getConfigInfo().get("comCode"));
|
|
|
- fcData.add("handToCount43T3_903", "");
|
|
|
- fcData.add("isCheckFlag", "1");
|
|
|
-
|
|
|
- HttpEntity<MultiValueMap<String, String>> fcRequestEntity = new HttpEntity<>(fcData, fcHeaders);
|
|
|
- ResponseEntity<String> fcResponse = getRestTemplate().postForEntity(
|
|
|
- BASE_URL + "/htcsp/QuotedPriceAction.do?cmd=getNoCarPreimum",
|
|
|
- fcRequestEntity, String.class);
|
|
|
-
|
|
|
- log.info("fcResponse: {}", fcResponse.getBody());
|
|
|
- Map<String, Object> res = OBJECT_MAPPER.readValue(fcResponse.getBody(), HashMap.class);
|
|
|
- return getStringValue(res, "premium");
|
|
|
+ MultiValueMap<String, String> fd = new LinkedMultiValueMap<>();
|
|
|
+ fd.add("noCarProductMes", personalInsuredJSON);
|
|
|
+ fd.add("quotationNo", quotationNo);
|
|
|
+ fd.add("comCode", attr.getConfigInfo().get("comCode"));
|
|
|
+ fd.add("handToCount43T3_903", "");
|
|
|
+ fd.add("isCheckFlag", "1");
|
|
|
+
|
|
|
+ String body = post(BASE_URL + "/htcsp/QuotedPriceAction.do?cmd=getNoCarPreimum",
|
|
|
+ buildNoCarPremiumHeaders(cookie), fd);
|
|
|
+ log.info("fcResponse: {}", body);
|
|
|
+ return str(MAPPER.readValue(body, HashMap.class), "premium");
|
|
|
} catch (Exception e) {
|
|
|
log.error("非车险保费获取失败: {}", e.getMessage());
|
|
|
return "";
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private HttpHeaders buildNoCarPremiumHeaders(String cookie) {
|
|
|
- HttpHeaders headers = new HttpHeaders();
|
|
|
- headers.add(HtRequestConstant.COOKIE, cookie);
|
|
|
- headers.add("Accept", "*/*");
|
|
|
- headers.add("Accept-Language", "zh-CN,zh;q=0.9");
|
|
|
- headers.add("Connection", "keep-alive");
|
|
|
- headers.add("Content-Type", CONTENT_TYPE_FORM);
|
|
|
- headers.add("Origin", ORIGIN);
|
|
|
- headers.add("Referer", REFERER_SAVE_ONE_STEP);
|
|
|
- headers.add("User-Agent", USER_AGENT);
|
|
|
- headers.add("X-Requested-With", X_REQUESTED_WITH);
|
|
|
- return headers;
|
|
|
- }
|
|
|
-
|
|
|
- private QuoteStepResult executeQuoteSteps(QuoteVo quoteVo, String quotationNo, LoginDTO loginDTO,
|
|
|
- String cookie, QuotePreResult preResult,
|
|
|
- Map<String, Object> gsInfo) throws Exception {
|
|
|
- // 报价第一步 保存车辆信息
|
|
|
- HttpHeaders headers2 = buildQuoteStep1Headers(cookie);
|
|
|
- HtCrawlerSaveOneStepRequest saveOneStepRequest = new HtCrawlerSaveOneStepRequest(
|
|
|
- quoteVo, preResult.carDTO(), preResult.parameters(), quotationNo,
|
|
|
- preResult.dataDTO(), loginDTO, gsInfo);
|
|
|
-
|
|
|
- ResponseEntity<Object> objectResponseEntity = htCrawlerRequestComponent.saveOneStept(saveOneStepRequest, headers2);
|
|
|
- String body = objectResponseEntity.getBody().toString();
|
|
|
+ private StepResult executeQuoteSteps(QuoteVo q, String quotationNo, LoginDTO dto,
|
|
|
+ String cookie, PreResult pre, Map<String, Object> gsInfo) throws Exception {
|
|
|
+ HttpHeaders h = buildQuoteStep1Headers(cookie);
|
|
|
+ HtCrawlerSaveOneStepRequest r = new HtCrawlerSaveOneStepRequest(q, pre.carDTO(), pre.params(), quotationNo, pre.dataDTO(), dto, gsInfo);
|
|
|
+ String body = req.saveOneStept(r, h).getBody().toString();
|
|
|
String mealid = extractMealId(body);
|
|
|
+ //机动车损失保险
|
|
|
+ String limitAmount = extractLimitAmount(body);
|
|
|
log.info("mealid: {}", mealid);
|
|
|
-
|
|
|
- // 驾意险处理
|
|
|
- String personalInsuredJSONString = buildPersonalInsuredJSON(quoteVo);
|
|
|
-
|
|
|
- // 报价第二步
|
|
|
- headers2 = buildQuoteStep2Headers(cookie);
|
|
|
- HtCrawlerQuoteRequest quoteRequest = new HtCrawlerQuoteRequest(quoteVo, mealid, "", personalInsuredJSONString);
|
|
|
- String decryptData = htCrawlerRequestComponent.quote(quoteRequest, headers2);
|
|
|
-
|
|
|
- // 错误处理
|
|
|
- handleQuoteErrors(decryptData, quoteVo, mealid, headers2, loginDTO);
|
|
|
-
|
|
|
- HtCrawlerQuoteResponse.DataDTO quoteResponseData = resolveQuoteResponse(quoteVo, decryptData, mealid, headers2, personalInsuredJSONString);
|
|
|
- return new QuoteStepResult(quoteResponseData, personalInsuredJSONString);
|
|
|
+ log.info("limitAmount: {}", limitAmount);
|
|
|
+ //组装驾意险参数,没有就空字符串
|
|
|
+ String personalInsuredJSON = buildPersonalInsuredJSON(q);
|
|
|
+
|
|
|
+ h = buildQuoteStep2Headers(cookie);
|
|
|
+ //组装报价参数
|
|
|
+ HtCrawlerQuoteRequest qr = new HtCrawlerQuoteRequest(q, mealid, limitAmount, "", personalInsuredJSON);
|
|
|
+ //报价第一次
|
|
|
+ String decryptData = req.quote(qr, h);
|
|
|
+ //处理重复投保返回终保日期的
|
|
|
+ q = handleQuoteErrors(decryptData, q);
|
|
|
+ //处理可能的录入的校验码有误
|
|
|
+ HtCrawlerQuoteResponse.DataDTO data = resolveQuoteResponse(q, decryptData, mealid, limitAmount, h, personalInsuredJSON);
|
|
|
+ return new StepResult(data, personalInsuredJSON);
|
|
|
}
|
|
|
|
|
|
private String extractMealId(String body) {
|
|
|
- Matcher matcher = PATTERN_MEAL_ID.matcher(body);
|
|
|
- return matcher.find() ? matcher.group(1) : "";
|
|
|
+ Matcher m = PAT_MEAL_ID.matcher(body);
|
|
|
+ return m.find() ? m.group(1) : "";
|
|
|
}
|
|
|
|
|
|
- // ====================== 驾意险处理 ======================
|
|
|
+ private String extractLimitAmount(String body) {
|
|
|
+ Matcher m = LIMIT_AMOUNT.matcher(body);
|
|
|
+ return m.find() ? m.group(1) : "";
|
|
|
+ }
|
|
|
|
|
|
- private String buildPersonalInsuredJSON(QuoteVo quoteVo) {
|
|
|
- if (quoteVo.getAccidentalDrivings() == null || quoteVo.getAccidentalDrivings().isEmpty()) {
|
|
|
- return "";
|
|
|
- }
|
|
|
+ // ====================== 驾意险组装 ======================
|
|
|
+ private String buildPersonalInsuredJSON(QuoteVo q) {
|
|
|
+ if (q.getAccidentalDrivings() == null || q.getAccidentalDrivings().isEmpty()) return "";
|
|
|
|
|
|
- List<Map<String, Object>> personalInsuredJSON = new ArrayList<>();
|
|
|
List<Map<String, Object>> perinsuredList = new ArrayList<>();
|
|
|
-
|
|
|
- JyxConfigVo lastConfigVo = null;
|
|
|
- jyxSetting lastSetting = null;
|
|
|
-
|
|
|
- for (AccidentalDrivingVo drivingDTO : quoteVo.getAccidentalDrivings()) {
|
|
|
- HttpResult<JyxConfigVo> configResult = platformClient.jyxConfigGetById(drivingDTO.getId());
|
|
|
- JyxConfigVo configVo = configResult.getData();
|
|
|
- lastConfigVo = configVo;
|
|
|
-
|
|
|
- int seatCount = Integer.parseInt(quoteVo.getCarInfoVo().getSeatCount());
|
|
|
- jyxSetting setting = configVo.getSettingList().stream()
|
|
|
- .filter(s -> s.getSeats() == seatCount)
|
|
|
- .findFirst()
|
|
|
- .orElse(null);
|
|
|
- lastSetting = setting;
|
|
|
-
|
|
|
- String productCode = configVo.getParentProductCode();
|
|
|
- perinsuredList.add(buildInsuredInfo(quoteVo, productCode));
|
|
|
- }
|
|
|
-
|
|
|
- personalInsuredJSON.add(buildAccidentalDriving(quoteVo, lastConfigVo, lastSetting, perinsuredList));
|
|
|
- return JSONObject.toJSONString(personalInsuredJSON);
|
|
|
- }
|
|
|
-
|
|
|
- private Map<String, Object> buildInsuredInfo(QuoteVo quoteVo, String productCode) {
|
|
|
- Map<String, Object> info = new HashMap<>();
|
|
|
- info.put("productcode", StringUtils.isEmpty(productCode) ? "E007" : productCode);
|
|
|
- info.put("mark", "1");
|
|
|
- info.put("insuredname", quoteVo.getInsuredPersonInfo().getName());
|
|
|
- info.put("certitype", "01");
|
|
|
- info.put("certicode", quoteVo.getInsuredPersonInfo().getIdentifyNumber());
|
|
|
- info.put("age", quoteVo.getInsuredPersonInfo().getBirthday().substring(0, 10));
|
|
|
- info.put("gender", quoteVo.getInsuredPersonInfo().getGender());
|
|
|
- info.put("perProWithCarStartDate", "");
|
|
|
- info.put("perProWithCarEndDate", "");
|
|
|
- info.put("relation", quoteVo.getOwnersInfo().getName().equals(quoteVo.getInsuredPersonInfo().getName()) ? "00" : "99");
|
|
|
- info.put("job", "");
|
|
|
- info.put("parentcode", "");
|
|
|
- info.put("parentname", "");
|
|
|
- info.put("parametercode", "");
|
|
|
- info.put("parametername", "");
|
|
|
- info.put("codecode", "");
|
|
|
- info.put("codecname", "");
|
|
|
- info.put("risktype", "");
|
|
|
- info.put("jobtype", "");
|
|
|
- info.put("customerno", "");
|
|
|
- info.put("workname", "");
|
|
|
- info.put("workphone", "");
|
|
|
- info.put("yearmoney", "");
|
|
|
- info.put("workaddress", "");
|
|
|
- info.put("otherphone", "");
|
|
|
- info.put("otheraddress", "");
|
|
|
- info.put("mobile", "");
|
|
|
- info.put("urgentname", "");
|
|
|
- info.put("urgentmobile", "");
|
|
|
- info.put("nationality", "CHN");
|
|
|
- return info;
|
|
|
- }
|
|
|
-
|
|
|
- private Map<String, Object> buildAccidentalDriving(QuoteVo quoteVo, JyxConfigVo configVo,
|
|
|
- jyxSetting setting, List<Map<String, Object>> perinsuredList) {
|
|
|
- Map<String, Object> driving = new HashMap<>();
|
|
|
- driving.put("butouflag", "");
|
|
|
- driving.put("amount", setting != null && setting.getCoverage() != null ?
|
|
|
- setting.getCoverage().toString().replace(".00", "") : "");
|
|
|
- driving.put("car_limitloadperson", StringUtils.isBlank(String.valueOf(setting.getSeats())) ? "" : setting.getSeats());
|
|
|
- driving.put("isInsuredPassenger", "");
|
|
|
- driving.put("productcode", configVo != null ? configVo.getParentProductCode() : "");
|
|
|
- driving.put("productname", "");
|
|
|
- driving.put("mealcode", configVo != null ? configVo.getProductCode() : "");
|
|
|
- driving.put("mealname", "");
|
|
|
- driving.put("startdate", quoteVo.getCiRiskInfoVo().getStartDate());
|
|
|
- driving.put("enddate", quoteVo.getCiRiskInfoVo().getEndDate());
|
|
|
- driving.put("num", "1");
|
|
|
- driving.put("premium", setting != null && setting.getPremium() != null ?
|
|
|
- setting.getPremium().toString().replace(".00", ".0") : "");
|
|
|
- driving.put("formationJudiciary", "");
|
|
|
- driving.put("argueJudiciary", "");
|
|
|
- driving.put("newCarSalesProvince", "");
|
|
|
- driving.put("newCarSalesCity", "");
|
|
|
- driving.put("newCarSalesDistrict", "");
|
|
|
- driving.put("buildYear", "");
|
|
|
- driving.put("xiangxiAddress", "");
|
|
|
- driving.put("postalCode", "");
|
|
|
- driving.put("bulidTypeCode", "");
|
|
|
- driving.put("bulidTypeQiTaMes", "");
|
|
|
- driving.put("provinceName", "");
|
|
|
- driving.put("cityName", "");
|
|
|
- driving.put("regionName", "");
|
|
|
- driving.put("isInsuredSizesFlag", "0");
|
|
|
- driving.put("perinsuredList", perinsuredList);
|
|
|
- driving.put("car_limitloadperson", quoteVo.getCarInfoVo().getSeatCount());
|
|
|
- return driving;
|
|
|
- }
|
|
|
-
|
|
|
- private void handleQuoteErrors(String decryptData, QuoteVo quoteVo, String mealid,
|
|
|
- HttpHeaders headers2, LoginDTO loginDTO) {
|
|
|
- boolean hasError = decryptData.contains("erroeInfo") || decryptData.contains("errrorFlag");
|
|
|
- if (!hasError) {
|
|
|
- return;
|
|
|
+ JyxConfigVo lastCfg = null;
|
|
|
+ jyxSetting lastSet = null;
|
|
|
+
|
|
|
+ for (AccidentalDrivingVo d : q.getAccidentalDrivings()) {
|
|
|
+ JyxConfigVo cfg = platformClient.jyxConfigGetById(d.getId()).getData();
|
|
|
+ lastCfg = cfg;
|
|
|
+ int seats = Integer.parseInt(q.getCarInfoVo().getSeatCount());
|
|
|
+ jyxSetting set = cfg.getSettingList().stream().filter(s -> s.getSeats() == seats).findFirst().orElse(null);
|
|
|
+ lastSet = set;
|
|
|
+ perinsuredList.add(buildInsuredInfo(q, cfg.getParentProductCode()));
|
|
|
}
|
|
|
-
|
|
|
- boolean isDuplicateWithEndDate = decryptData.contains("发生重复投保") && decryptData.contains("终保日期");
|
|
|
- boolean isCheckCodeError = decryptData.contains("录入的校验码有误");
|
|
|
-
|
|
|
- if (isDuplicateWithEndDate || isCheckCodeError) {
|
|
|
- handleDuplicateInsurance(decryptData, quoteVo, mealid, headers2, loginDTO);
|
|
|
- return;
|
|
|
+ return JSONObject.toJSONString(List.of(buildAccidentalDriving(q, lastCfg, lastSet, perinsuredList)));
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, Object> buildInsuredInfo(QuoteVo q, String productCode) {
|
|
|
+ Map<String, Object> m = new HashMap<>();
|
|
|
+ m.put("productcode", StringUtils.isEmpty(productCode) ? "E007" : productCode);
|
|
|
+ m.put("mark", "1");
|
|
|
+ m.put("insuredname", q.getInsuredPersonInfo().getName());
|
|
|
+ m.put("certitype", "01");
|
|
|
+ m.put("certicode", q.getInsuredPersonInfo().getIdentifyNumber());
|
|
|
+ m.put("age", q.getInsuredPersonInfo().getBirthday().substring(0, 10));
|
|
|
+ m.put("gender", q.getInsuredPersonInfo().getGender());
|
|
|
+ m.put("relation", q.getOwnersInfo().getName().equals(q.getInsuredPersonInfo().getName()) ? "00" : "99");
|
|
|
+ m.put("nationality", "CHN");
|
|
|
+ // 其余字段均为空
|
|
|
+ for (String k : List.of("perProWithCarStartDate", "perProWithCarEndDate", "job", "parentcode", "parentname",
|
|
|
+ "parametercode", "parametername", "codecode", "codecname", "risktype", "jobtype", "customerno",
|
|
|
+ "workname", "workphone", "yearmoney", "workaddress", "otherphone", "otheraddress",
|
|
|
+ "mobile", "urgentname", "urgentmobile")) {
|
|
|
+ m.put(k, "");
|
|
|
}
|
|
|
-
|
|
|
- // 其余所有错误直接抛出
|
|
|
- throwQuoteError(decryptData);
|
|
|
+ return m;
|
|
|
}
|
|
|
|
|
|
- private void throwQuoteError(String decryptData) {
|
|
|
- HtCrawlerQuoteResponse.DataErrDTO dataErr = JSONObject.parseObject(decryptData, HtCrawlerQuoteResponse.DataErrDTO.class);
|
|
|
- String errorInfo = dataErr.getErroeInfo();
|
|
|
- int index = errorInfo.indexOf(CHINA);
|
|
|
- String message = index >= 0 ? errorInfo.substring(index) : errorInfo;
|
|
|
- throw new RuntimeException(ERROR_PREFIX + message);
|
|
|
- }
|
|
|
+ private Map<String, Object> buildAccidentalDriving(QuoteVo q, JyxConfigVo cfg, jyxSetting set,
|
|
|
+ List<Map<String, Object>> perinsuredList) {
|
|
|
+ Map<String, Object> m = new HashMap<>();
|
|
|
+ for (String k : List.of("butouflag", "isInsuredPassenger", "productname", "mealname", "formationJudiciary",
|
|
|
+ "argueJudiciary", "newCarSalesProvince", "newCarSalesCity", "newCarSalesDistrict", "buildYear", "xiangxiAddress",
|
|
|
+ "postalCode", "bulidTypeCode", "bulidTypeQiTaMes", "provinceName", "cityName", "regionName")) {
|
|
|
+ m.put(k, "");
|
|
|
+ }
|
|
|
+ m.put("amount", set != null && set.getCoverage() != null ? set.getCoverage().toString().replace(".00", "") : "");
|
|
|
+ m.put("car_limitloadperson", q.getCarInfoVo().getSeatCount());
|
|
|
+ m.put("productcode", cfg != null ? cfg.getParentProductCode() : "");
|
|
|
+ m.put("mealcode", cfg != null ? cfg.getProductCode() : "");
|
|
|
+ m.put("startdate", q.getCiRiskInfoVo().getStartDate());
|
|
|
+ m.put("enddate", q.getCiRiskInfoVo().getEndDate());
|
|
|
+ m.put("num", "1");
|
|
|
+ m.put("premium", set != null && set.getPremium() != null ? set.getPremium().toString().replace(".00", ".0") : "");
|
|
|
+ m.put("isInsuredSizesFlag", "0");
|
|
|
+ m.put("perinsuredList", perinsuredList);
|
|
|
+ return m;
|
|
|
+ }
|
|
|
+
|
|
|
+ // ====================== 报价错误处理 ======================
|
|
|
+ private QuoteVo handleQuoteErrors(String decryptData, QuoteVo q) {
|
|
|
+ boolean hasError = decryptData.contains("erroeInfo") || decryptData.contains("errrorFlag");
|
|
|
+ if (!hasError) return q;
|
|
|
|
|
|
- private void handleDuplicateInsurance(String decryptData, QuoteVo quoteVo, String mealid,
|
|
|
- HttpHeaders headers2, LoginDTO loginDTO) {
|
|
|
- HtCrawlerQuoteResponse.DataErrDTO dataErrDTO = JSONObject.parseObject(decryptData, HtCrawlerQuoteResponse.DataErrDTO.class);
|
|
|
- Matcher matcher = PATTERN_END_DATE.matcher(decryptData);
|
|
|
+ boolean dup = decryptData.contains("发生重复投保") && decryptData.contains("终保日期");
|
|
|
|
|
|
- if (matcher.find()) {
|
|
|
- String endDate = matcher.group(1).trim();
|
|
|
- String startDate = endDate + ":00";
|
|
|
- quoteVo.getCiRiskInfoVo().setStartDate(startDate);
|
|
|
- try {
|
|
|
- LocalDateTime dateTime = LocalDateTime.parse(
|
|
|
- startDate.replace(" ", "T"),
|
|
|
- DateTimeFormatter.ofPattern(DATE_FORMAT_T));
|
|
|
- String newStartDate = dateTime.format(DateTimeFormatter.ofPattern(DATE_FORMAT));
|
|
|
- String newEndDate = dateTime.plusYears(1).minusDays(1).format(DateTimeFormatter.ofPattern(DATE_FORMAT));
|
|
|
-
|
|
|
- quoteVo.getCiRiskInfoVo().setStartDate(newStartDate.substring(0, 10) + " 00:00:00");
|
|
|
- quoteVo.getCiRiskInfoVo().setEndDate(newEndDate.substring(0, 10) + " 23:59:59");
|
|
|
-
|
|
|
- log.info("发生重复投保,重新设置 起保日期: {}, 终保日期: {}",
|
|
|
- quoteVo.getCiRiskInfoVo().getStartDate(),
|
|
|
- quoteVo.getCiRiskInfoVo().getEndDate());
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("日期解析失败: {}", e.getMessage());
|
|
|
- }
|
|
|
- // 递归重新报价 - 注意:这里存在潜在的无限递归风险,建议后续改为循环
|
|
|
- // 为保持原有逻辑,保留递归调用
|
|
|
+ if (dup) {
|
|
|
+ q = handleDuplicateInsurance(decryptData, q);
|
|
|
+ return q;
|
|
|
}
|
|
|
+ return q;
|
|
|
}
|
|
|
|
|
|
- private HtCrawlerQuoteResponse.DataDTO resolveQuoteResponse(QuoteVo quoteVo, String decryptData, String mealid,
|
|
|
- HttpHeaders headers2, String personalInsuredJSONString) throws Exception {
|
|
|
- HtCrawlerQuoteResponse.DataDTO quoteResponseData = JSONObject.parseObject(decryptData, HtCrawlerQuoteResponse.DataDTO.class);
|
|
|
-
|
|
|
- List<HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO> basePartList =
|
|
|
- quoteResponseData.getBasepartdtolist() != null ? quoteResponseData.getBasepartdtolist().getBasepartdto() : null;
|
|
|
+ private QuoteVo handleDuplicateInsurance(String decryptData, QuoteVo q) {
|
|
|
+ Matcher m = PAT_END_DATE.matcher(decryptData);
|
|
|
+ if (!m.find()) return q;
|
|
|
|
|
|
- if (quoteResponseData.getApplicationdto() == null && basePartList != null) {
|
|
|
- int size = basePartList.size();
|
|
|
- if (size >= 1 && size <= 3) {
|
|
|
- String basePartJSON = buildBasePartJSON(basePartList, size);
|
|
|
- HtCrawlerQuoteRequest quoteRequest = new HtCrawlerQuoteRequest(quoteVo, mealid, basePartJSON, personalInsuredJSONString);
|
|
|
- decryptData = htCrawlerRequestComponent.quote(quoteRequest, headers2);
|
|
|
- log.info("quoteResponseData:{}: {}", size, JSONObject.toJSONString(decryptData));
|
|
|
- quoteResponseData = JSONObject.parseObject(decryptData, HtCrawlerQuoteResponse.DataDTO.class);
|
|
|
+ String end = m.group(1).trim();
|
|
|
+ String start = end + ":00";
|
|
|
+ q.getCiRiskInfoVo().setStartDate(start);
|
|
|
+ try {
|
|
|
+ LocalDateTime dt = LocalDateTime.parse(start.replace(" ", "T"), DateTimeFormatter.ofPattern(DATE_FMT_T));
|
|
|
+ String newStart = dt.format(DateTimeFormatter.ofPattern(DATE_FMT));
|
|
|
+ String newEnd = dt.plusYears(1).minusDays(1).format(DateTimeFormatter.ofPattern(DATE_FMT));
|
|
|
+ q.getCiRiskInfoVo().setStartDate(newStart.substring(0, 10) + " 00:00:00");
|
|
|
+ q.getCiRiskInfoVo().setEndDate(newEnd.substring(0, 10) + " 23:59:59");
|
|
|
+ log.info("重复投保,重新设置 起保: {}, 终保: {}", q.getCiRiskInfoVo().getStartDate(), q.getCiRiskInfoVo().getEndDate());
|
|
|
+ return q;
|
|
|
+ } catch (Exception e) { log.error("日期解析失败: {}", e.getMessage()); }
|
|
|
+ return q;
|
|
|
+ }
|
|
|
+
|
|
|
+ private HtCrawlerQuoteResponse.DataDTO resolveQuoteResponse(QuoteVo q, String decryptData, String mealid, String limitAmount,
|
|
|
+ HttpHeaders h, String personalInsuredJSON) throws Exception {
|
|
|
+ HtCrawlerQuoteResponse.DataDTO data = JSONObject.parseObject(decryptData, HtCrawlerQuoteResponse.DataDTO.class);
|
|
|
+ if (data.getApplicationdto() != null) return data;
|
|
|
+
|
|
|
+ List<HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO> list =
|
|
|
+ data.getBasepartdtolist() != null ? data.getBasepartdtolist().getBasepartdto() : null;
|
|
|
+ if (list == null || list.isEmpty() || list.size() > 3) return data;
|
|
|
+
|
|
|
+ for (int i = 0; i < MAX_RETRIES; i++) {
|
|
|
+ String basePartJSON = buildBasePartJSON(list);
|
|
|
+ String response = req.quote(new HtCrawlerQuoteRequest(q, mealid, limitAmount, basePartJSON, personalInsuredJSON), h);
|
|
|
+ log.info("resolveQuoteResponse attempt {}/{}: {}", i + 1, MAX_RETRIES, response);
|
|
|
+
|
|
|
+ HtCrawlerQuoteResponse.DataDTO result = JSONObject.parseObject(response, HtCrawlerQuoteResponse.DataDTO.class);
|
|
|
+ if (result != null && result.getApplicationdto() != null) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
|
|
|
- if (quoteResponseData == null || decryptData.contains("erroeInfo")) {
|
|
|
- HtCrawlerQuoteResponse.DataErrDTO dataErr = JSONObject.parseObject(decryptData, HtCrawlerQuoteResponse.DataErrDTO.class);
|
|
|
- throw new Exception(ERROR_PREFIX + dataErr.getErroeInfo());
|
|
|
+ // autocheckcode 可能不准确,重新获取 quote 刷新验证码
|
|
|
+ if (response.contains("录入的校验码有误") && i < MAX_RETRIES - 1) {
|
|
|
+ log.warn("autocheckcode 校验失败,重新获取 quote 刷新验证码 (attempt {}/{})", i + 1, MAX_RETRIES);
|
|
|
+ // 必须传空 basePart,接口才会返回新的 basePart 列表(含新 autocheckcode)
|
|
|
+ String fresh = req.quote(new HtCrawlerQuoteRequest(q, mealid, limitAmount, "", personalInsuredJSON), h);
|
|
|
+ result = JSONObject.parseObject(fresh, HtCrawlerQuoteResponse.DataDTO.class);
|
|
|
+ if (result != null && result.getApplicationdto() != null) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ // 用新的 basePart 列表更新 list,下一轮循环会自动重新 buildBasePartJSON
|
|
|
+ list = result != null && result.getBasepartdtolist() != null
|
|
|
+ ? result.getBasepartdtolist().getBasepartdto() : null;
|
|
|
+ if (list == null || list.isEmpty() || list.size() > 3) {
|
|
|
+ return result != null ? result : data;
|
|
|
}
|
|
|
+ continue;
|
|
|
}
|
|
|
- }
|
|
|
- return quoteResponseData;
|
|
|
- }
|
|
|
-
|
|
|
- private String buildBasePartJSON(List<HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO> basePartList, int size) {
|
|
|
- StringBuilder sb = new StringBuilder("[");
|
|
|
- for (int i = 0; i < size; i++) {
|
|
|
- HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO dto = basePartList.get(i);
|
|
|
- String querrysequenceno = dto.getQuerrysequenceno();
|
|
|
- String autocheckcode = dto.getAutocheckcode();
|
|
|
- String riskfalg = i == 0 ? "0" : (i == 1 ? "1" : "2");
|
|
|
- if (size == 1) {
|
|
|
- riskfalg = "0".equals(querrysequenceno.substring(0, 1)) ? "0" : "1";
|
|
|
+
|
|
|
+ if (response.contains("erroeInfo")) {
|
|
|
+ throw new Exception(ERR_PREFIX + JSONObject.parseObject(response, HtCrawlerQuoteResponse.DataErrDTO.class).getErroeInfo());
|
|
|
}
|
|
|
- if (i > 0) sb.append(",");
|
|
|
- sb.append(String.format("{\"riskfalg\":\"%s\",\"checktype\":2,\"querysequenceno\":\"%s\",\"checkcode\":\"%s\",\"answer\":\"\"}",
|
|
|
- riskfalg, querrysequenceno, autocheckcode));
|
|
|
+ return result != null ? result : data;
|
|
|
+ }
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String buildBasePartJSON(List<HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO> list) {
|
|
|
+ int size = list.size();
|
|
|
+ String basePartJSON = "";
|
|
|
+ if (size == 1) {
|
|
|
+ HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO basePartDTO = list.get(0);
|
|
|
+ log.info("buildBasePartJSON0: {}, {}", size, JSONObject.toJSONString(basePartDTO));
|
|
|
+ String querrysequenceno = basePartDTO.getQuerrysequenceno();
|
|
|
+ String autocheckcode = basePartDTO.getAutocheckcode();
|
|
|
+ String riskfalg = "0".equals(querrysequenceno.substring(0, 1)) ? "0" : "1";
|
|
|
+ basePartJSON = "[{'riskfalg':'"+riskfalg+"','checktype':2,'querysequenceno':'"+querrysequenceno+"','checkcode':'"+autocheckcode+"','answer':''}]";
|
|
|
+ }
|
|
|
+ if (size == 2) {
|
|
|
+ HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO basePartDTO = list.get(0);
|
|
|
+ log.info("buildBasePartJSON0: {}, {}", size, JSONObject.toJSONString(basePartDTO));
|
|
|
+ String querrysequenceno = basePartDTO.getQuerrysequenceno();
|
|
|
+ String autocheckcode = basePartDTO.getAutocheckcode();
|
|
|
+ HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO basePartDTO1 = list.get(1);
|
|
|
+ log.info("buildBasePartJSON1: {}, {}", size, JSONObject.toJSONString(basePartDTO1));
|
|
|
+ String querrysequenceno1 = basePartDTO1.getQuerrysequenceno();
|
|
|
+ String autocheckcode1 = basePartDTO1.getAutocheckcode();
|
|
|
+ basePartJSON = "[{'riskfalg':'0','checktype':2,'querysequenceno':'"+querrysequenceno1+"','checkcode':'"+autocheckcode1+"','answer':''}," +
|
|
|
+ "{'riskfalg':'1','checktype':2,'querysequenceno':'"+querrysequenceno+"','checkcode':'"+autocheckcode+"','answer':''}]";
|
|
|
+ }
|
|
|
+ if (size == 3) {
|
|
|
+ HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO basePartDTO = list.get(0);
|
|
|
+ log.info("buildBasePartJSON0: {}, {}", size, JSONObject.toJSONString(basePartDTO));
|
|
|
+ String querrysequenceno = basePartDTO.getQuerrysequenceno();
|
|
|
+ String autocheckcode = basePartDTO.getAutocheckcode();
|
|
|
+ HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO basePartDTO1 = list.get(1);
|
|
|
+ log.info("buildBasePartJSON1: {}, {}", size, JSONObject.toJSONString(basePartDTO1));
|
|
|
+ String querrysequenceno1 = basePartDTO1.getQuerrysequenceno();
|
|
|
+ String autocheckcode1 = basePartDTO1.getAutocheckcode();
|
|
|
+ HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO basePartDTO2 = list.get(2);
|
|
|
+ log.info("buildBasePartJSON2: {}, {}", size, JSONObject.toJSONString(basePartDTO2));
|
|
|
+ String querrysequenceno2 = basePartDTO2.getQuerrysequenceno();
|
|
|
+ String autocheckcode2 = basePartDTO2.getAutocheckcode();
|
|
|
+ basePartJSON = "[{'riskfalg':'0','checktype':2,'querysequenceno':'"+querrysequenceno1+"','checkcode':'"+autocheckcode1+"','answer':''}," +
|
|
|
+ "{'riskfalg':'1','checktype':2,'querysequenceno':'"+querrysequenceno+"','checkcode':'"+autocheckcode+"','answer':''}," +
|
|
|
+ "{'riskfalg':'2','checktype':2,'querysequenceno':'"+querrysequenceno2+"','checkcode':'"+autocheckcode2+"','answer':''}]";
|
|
|
}
|
|
|
- sb.append("]");
|
|
|
- return sb.toString();
|
|
|
+ return basePartJSON;
|
|
|
}
|
|
|
|
|
|
// ====================== 核保 ======================
|
|
|
-
|
|
|
@Override
|
|
|
- public UnderwritingResultsVo underwriting(UnderwritingVo underwritingVo) throws JsonProcessingException {
|
|
|
- AttributionInformationVo attributionInformationVo = underwritingVo.getOrder().getAttributionInformationVo();
|
|
|
- HtCrawlerConfigureParameters parameters = ConfigureParametersConversion.conversionEntity(
|
|
|
- HtCrawlerConfigureParameters.class, attributionInformationVo.getConfigInfo());
|
|
|
- doLoginCookie(attributionInformationVo);
|
|
|
-
|
|
|
- HttpHeaders headers = htCrawlerRequestComponent.getHeaders();
|
|
|
- HtCrawlerOrder order = htCrawlerOrderService.findByOrdersNo(underwritingVo.getOrder().getOrdersNo());
|
|
|
- underwritingVo.getOrder().setQuoteNo(order.getQuotationRelaNo());
|
|
|
-
|
|
|
- String ciCategory = order.getCiCategory();
|
|
|
- String biCategory = order.getBiCategory();
|
|
|
- HtCrawlerSubmitRequest submitRequest = new HtCrawlerSubmitRequest(underwritingVo, parameters, ciCategory, biCategory);
|
|
|
- UnderwritingResultsVo result = new UnderwritingResultsVo();
|
|
|
-
|
|
|
- String res = htCrawlerRequestComponent.submit2(submitRequest, headers);
|
|
|
- Map<String, Object> map = OBJECT_MAPPER.readValue(res, Map.class);
|
|
|
-
|
|
|
- // 评分不达标或其他错误
|
|
|
- if (isUnderwritingFailed(ciCategory, map, res)) {
|
|
|
- result.setUnderwritingStatus(InsOrderStatusEnum.WAIT_AUDIT);
|
|
|
- throw new SystemException("核保失败" + "-------" + map.get("MSG"));
|
|
|
- }
|
|
|
- if (map.toString().contains("起保时间不正确")) {
|
|
|
- throw new SystemException("起保时间不正确-------即时起保分钟数必须为00/15/30/45\n请重新选择起保时间!");
|
|
|
- }
|
|
|
+ public UnderwritingResultsVo underwriting(UnderwritingVo vo) throws JsonProcessingException {
|
|
|
+ AttributionInformationVo attr = vo.getOrder().getAttributionInformationVo();
|
|
|
+ HtCrawlerConfigureParameters params = ConfigureParametersConversion.conversionEntity(
|
|
|
+ HtCrawlerConfigureParameters.class, attr.getConfigInfo());
|
|
|
+ doLoginCookie(attr);
|
|
|
|
|
|
- if (map.toString().contains("需转人工核保")) {
|
|
|
- return handleManualUnderwriting(order, parameters, result);
|
|
|
- }
|
|
|
+ HtCrawlerOrder order = orderService.findByOrdersNo(vo.getOrder().getOrdersNo());
|
|
|
+ vo.getOrder().setQuoteNo(order.getQuotationRelaNo());
|
|
|
+
|
|
|
+ HtCrawlerSubmitRequest submit = new HtCrawlerSubmitRequest(vo, params, order.getCiCategory(), order.getBiCategory());
|
|
|
+ String res = req.submit2(submit, req.getHeaders());
|
|
|
+ Map<String, Object> map = MAPPER.readValue(res, Map.class);
|
|
|
|
|
|
- if (res.contains("已通过核保未实收") || isPassHB(map)) {
|
|
|
- return handlePassedUnderwriting(order, parameters, result, underwritingVo);
|
|
|
+ if (isUnderwritingFailed(order.getCiCategory(), map, res)) {
|
|
|
+ throw new SystemException("核保失败-------" + map.get("MSG"));
|
|
|
}
|
|
|
+ if (res.contains("起保时间不正确")) {
|
|
|
+ throw new SystemException("起保时间不正确-------即时起保分钟数必须为00/15/30/45\n请重新选择起保时间!");
|
|
|
+ }
|
|
|
+ if (res.contains("需转人工核保")) return handleManualUnderwriting(order, params);
|
|
|
+ if (res.contains("已通过核保未实收") || isPassHB(map)) return handlePassedUnderwriting(order, params, vo);
|
|
|
|
|
|
- result.setUnderwritingStatus(InsOrderStatusEnum.WAIT_AUDIT);
|
|
|
- return result;
|
|
|
+ UnderwritingResultsVo r = new UnderwritingResultsVo();
|
|
|
+ r.setUnderwritingStatus(InsOrderStatusEnum.WAIT_AUDIT);
|
|
|
+ return r;
|
|
|
}
|
|
|
|
|
|
- private boolean isUnderwritingFailed(String ciCategory, Map<String, Object> map, String res) {
|
|
|
- return !"1,2,3,4".contains(ciCategory)
|
|
|
- || (map.get("isOver") != null && "Y".equals(map.get("isOver").toString()))
|
|
|
- || (map.get("MSG") != null && "重新计算保费".equals(map.get("MSG").toString()))
|
|
|
+ private boolean isUnderwritingFailed(String ci, Map<String, Object> m, String res) {
|
|
|
+ return !"1,2,3,4".contains(ci)
|
|
|
+ || "Y".equals(str(m, "isOver"))
|
|
|
+ || "重新计算保费".equals(str(m, "MSG"))
|
|
|
|| res.contains("强制下发修改意见");
|
|
|
}
|
|
|
|
|
|
- private boolean isPassHB(Map<String, Object> map) {
|
|
|
- return map.get("isPassHB") != null && "Y".equals(map.get("isPassHB").toString());
|
|
|
- }
|
|
|
+ private boolean isPassHB(Map<String, Object> m) { return "Y".equals(str(m, "isPassHB")); }
|
|
|
|
|
|
- private UnderwritingResultsVo handleManualUnderwriting(HtCrawlerOrder order, HtCrawlerConfigureParameters parameters,
|
|
|
- UnderwritingResultsVo result) {
|
|
|
+ private UnderwritingResultsVo handleManualUnderwriting(HtCrawlerOrder order, HtCrawlerConfigureParameters params) {
|
|
|
try {
|
|
|
- HttpHeaders headers = buildManualUnderwritingHeaders();
|
|
|
- String url = BASE_URL + "/htcsp/checkInsAction.do";
|
|
|
- MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
|
|
- params.add("cmd", "submitZRG");
|
|
|
+ // 提交人工核保
|
|
|
MultiValueMap<String, String> data = new LinkedMultiValueMap<>();
|
|
|
- data.add("zrgms", "");
|
|
|
- data.add("zrgpriority", "1");
|
|
|
-
|
|
|
- HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(data, headers);
|
|
|
- ResponseEntity<String> response = CookieUtils.getRestTemplate().exchange(
|
|
|
- UriComponentsBuilder.fromHttpUrl(url).queryParams(params).toUriString(),
|
|
|
- HttpMethod.POST, request, String.class);
|
|
|
-
|
|
|
- Map<String, Object> body = OBJECT_MAPPER.readValue(response.getBody(), Map.class);
|
|
|
- result.setUnderwritingStatus(InsOrderStatusEnum.PAY_PENDING);
|
|
|
- result.setCompanyOrderNo(body.get("quotationno") != null ? body.get("quotationno").toString() : "");
|
|
|
- result.setJqApplyNo(body.get("proposal_no_jq") != null ? body.get("proposal_no_jq").toString() : "");
|
|
|
- result.setSyApplyNo(body.get("proposal_no_sy") != null ? body.get("proposal_no_sy").toString() : "");
|
|
|
-
|
|
|
- // 获取支付链接
|
|
|
- headers = buildPaymentLinkHeaders();
|
|
|
- url = BASE_URL + "/htcsp/checkInsAction.do?cmd=queryUnderwriterAdvice";
|
|
|
- MultiValueMap<String, String> data2 = new LinkedMultiValueMap<>();
|
|
|
- data2.add("businessNo", order.getQuotationRelaNo());
|
|
|
- data2.add("excet", "");
|
|
|
- request = new HttpEntity<>(data2, headers);
|
|
|
- ResponseEntity<String> response2 = CookieUtils.getRestTemplate().exchange(
|
|
|
- UriComponentsBuilder.fromHttpUrl(url).toUriString(),
|
|
|
- HttpMethod.POST, request, String.class);
|
|
|
-
|
|
|
- if (response2.getBody().contains("审核通过")) {
|
|
|
- HtCrawlerPaymentLinkRequest paymentLinkRequest = new HtCrawlerPaymentLinkRequest(parameters, new PaymentLinkVo(), response2.getBody());
|
|
|
- HtCrawlerPaymentLinkResponse paymentLinkResponse = htCrawlerRequestComponent.getPaymentLink(paymentLinkRequest, headers);
|
|
|
- result.setPaymentLink(paymentLinkResponse.getImg());
|
|
|
- result.setUnderwritingStatus(InsOrderStatusEnum.PAY_PENDING);
|
|
|
- return result;
|
|
|
- } else {
|
|
|
- result.setUnderwritingStatus(InsOrderStatusEnum.WAIT_AUDIT);
|
|
|
- String body2 = response2.getBody();
|
|
|
- int start = body2.indexOf("原因");
|
|
|
- int end = body2.lastIndexOf("。");
|
|
|
- String reason = (start >= 0 && end > start) ? body2.substring(start, end) : "审核未通过";
|
|
|
- throw new SystemException("审核未通过:" + reason);
|
|
|
- }
|
|
|
- } catch (Exception e) {
|
|
|
- result.setUnderwritingStatus(InsOrderStatusEnum.WAIT_AUDIT);
|
|
|
- if (e instanceof SystemException) {
|
|
|
- throw (SystemException) e;
|
|
|
+ data.add("zrgms", ""); data.add("zrgpriority", "1");
|
|
|
+ String url = BASE_URL + "/htcsp/checkInsAction.do";
|
|
|
+ Map<String, Object> body = exchangeForm(url, Map.of("cmd", "submitZRG"), data, buildManualUwHeaders());
|
|
|
+
|
|
|
+ UnderwritingResultsVo r = new UnderwritingResultsVo();
|
|
|
+ r.setUnderwritingStatus(InsOrderStatusEnum.PAY_PENDING);
|
|
|
+ r.setCompanyOrderNo(str(body, "quotationno"));
|
|
|
+ r.setJqApplyNo(str(body, "proposal_no_jq"));
|
|
|
+ r.setSyApplyNo(str(body, "proposal_no_sy"));
|
|
|
+
|
|
|
+ // 查询支付链接
|
|
|
+ String url2 = BASE_URL + "/htcsp/checkInsAction.do?cmd=queryUnderwriterAdvice";
|
|
|
+ MultiValueMap<String, String> d2 = new LinkedMultiValueMap<>();
|
|
|
+ d2.add("businessNo", order.getQuotationRelaNo()); d2.add("excet", "");
|
|
|
+ String html = String.valueOf(exchangeForm(url2, null, d2, buildPaymentLinkHeaders()));
|
|
|
+
|
|
|
+ if (html.contains("审核通过")) {
|
|
|
+ HtCrawlerPaymentLinkResponse pl = req.getPaymentLink(
|
|
|
+ new HtCrawlerPaymentLinkRequest(params, new PaymentLinkVo(), html), buildPaymentLinkHeaders());
|
|
|
+ r.setPaymentLink(pl.getImg());
|
|
|
+ r.setUnderwritingStatus(InsOrderStatusEnum.PAY_PENDING);
|
|
|
+ return r;
|
|
|
}
|
|
|
+ int s = html.indexOf("原因"), e = html.lastIndexOf("。");
|
|
|
+ throw new SystemException("审核未通过:" + (s >= 0 && e > s ? html.substring(s, e) : "审核未通过"));
|
|
|
+ } catch (SystemException se) { throw se; }
|
|
|
+ catch (Exception e) {
|
|
|
log.error("人工核保处理异常", e);
|
|
|
- return result;
|
|
|
+ UnderwritingResultsVo r = new UnderwritingResultsVo();
|
|
|
+ r.setUnderwritingStatus(InsOrderStatusEnum.WAIT_AUDIT);
|
|
|
+ return r;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private UnderwritingResultsVo handlePassedUnderwriting(HtCrawlerOrder order, HtCrawlerConfigureParameters parameters,
|
|
|
- UnderwritingResultsVo result, UnderwritingVo underwritingVo) {
|
|
|
- HtCrawlerPaymentLinkResponse paymentLinkResponse = queryPaymentLink(order, parameters, new PaymentLinkVo());
|
|
|
- log.info("paymentLinkResponse: {}", JSONObject.toJSONString(paymentLinkResponse));
|
|
|
-
|
|
|
- result.setPaymentLink(paymentLinkResponse.getImg());
|
|
|
- underwritingVo.getInsOrders().setPayLink(paymentLinkResponse.getImg());
|
|
|
- underwritingVo.getInsOrders().setAuditTime(LocalDateTime.now());
|
|
|
- underwritingVo.getInsOrders().setCompanyOrderNo(order.getQuotationRelaNo());
|
|
|
- result.setUnderwritingStatus(InsOrderStatusEnum.PAY_PENDING);
|
|
|
- return result;
|
|
|
+ private UnderwritingResultsVo handlePassedUnderwriting(HtCrawlerOrder order, HtCrawlerConfigureParameters params, UnderwritingVo vo) {
|
|
|
+ HtCrawlerPaymentLinkResponse pl = queryPaymentLink(order, params, new PaymentLinkVo());
|
|
|
+ log.info("paymentLinkResponse: {}", JSONObject.toJSONString(pl));
|
|
|
+ vo.getInsOrders().setPayLink(pl.getImg());
|
|
|
+ vo.getInsOrders().setAuditTime(LocalDateTime.now());
|
|
|
+ vo.getInsOrders().setCompanyOrderNo(order.getQuotationRelaNo());
|
|
|
+ UnderwritingResultsVo r = new UnderwritingResultsVo();
|
|
|
+ r.setPaymentLink(pl.getImg());
|
|
|
+ r.setUnderwritingStatus(InsOrderStatusEnum.PAY_PENDING);
|
|
|
+ return r;
|
|
|
}
|
|
|
|
|
|
// ====================== 支付链接 ======================
|
|
|
-
|
|
|
@Override
|
|
|
- public PaymentLinkResultsVo getPaymentLink(PaymentLinkVo paymentLinkVo) {
|
|
|
- AttributionInformationVo attributionInformationVo = paymentLinkVo.getOrder().getAttributionInformationVo();
|
|
|
- doLoginCookie(attributionInformationVo);
|
|
|
- HtCrawlerOrder order = htCrawlerOrderService.findByOrdersNo(paymentLinkVo.getOrder().getOrdersNo());
|
|
|
-
|
|
|
- HtCrawlerConfigureParameters parameters = ConfigureParametersConversion.conversionEntity(
|
|
|
- HtCrawlerConfigureParameters.class, attributionInformationVo.getConfigInfo());
|
|
|
-
|
|
|
- HtCrawlerPaymentLinkResponse paymentLinkResponse = queryPaymentLink(order, parameters, paymentLinkVo);
|
|
|
- log.info("paymentLinkResponse: {}", JSONObject.toJSONString(paymentLinkResponse));
|
|
|
- return new PaymentLinkResultsVo(true, paymentLinkResponse.getImg(), paymentLinkResponse.getErrorInfo());
|
|
|
- }
|
|
|
-
|
|
|
- private HtCrawlerPaymentLinkResponse queryPaymentLink(HtCrawlerOrder order,
|
|
|
- HtCrawlerConfigureParameters parameters,
|
|
|
- PaymentLinkVo paymentLinkVo) {
|
|
|
- HttpHeaders headers = buildPaymentListHeaders(htCrawlerRequestComponent.getCookie());
|
|
|
- String url = BASE_URL + "/htcsp/PaymentAction.do";
|
|
|
-
|
|
|
- MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
|
|
- params.add("cmd", "queryPaymentList");
|
|
|
- params.add("paytype", "jianfei");
|
|
|
- params.add("Single_system", "10000");
|
|
|
- params.add("checkStatus", "1");
|
|
|
- params.add("quotationno", order.getQuotationRelaNo());
|
|
|
-
|
|
|
- HttpEntity<Void> request = new HttpEntity<>(null, headers);
|
|
|
- ResponseEntity<String> response = CookieUtils.getRestTemplate().exchange(
|
|
|
- UriComponentsBuilder.fromHttpUrl(url).queryParams(params).toUriString(),
|
|
|
- HttpMethod.GET, request, String.class);
|
|
|
-
|
|
|
- String responseBody = response.getBody();
|
|
|
- log.info("queryPaymentList response: {}", responseBody);
|
|
|
- HtCrawlerPaymentLinkRequest paymentLinkRequest = new HtCrawlerPaymentLinkRequest(parameters, paymentLinkVo, responseBody);
|
|
|
- return htCrawlerRequestComponent.getPaymentLink(paymentLinkRequest, headers);
|
|
|
- }
|
|
|
-
|
|
|
- // ====================== 登录Cookie检查 ======================
|
|
|
-
|
|
|
- private void doLoginCookie(AttributionInformationVo attributionInformationVo) {
|
|
|
- if (StringUtils.isBlank(htCrawlerRequestComponent.getCookie())) {
|
|
|
- LoginDTO loginDTO = buildLoginDTO(attributionInformationVo);
|
|
|
- Map<String, Object> mmap = login(loginDTO);
|
|
|
- String cookie = (String) mmap.get("cookie");
|
|
|
- htCrawlerRequestComponent.getHeaders().remove(HtRequestConstant.COOKIE);
|
|
|
- htCrawlerRequestComponent.getHeaders().add(HtRequestConstant.COOKIE, cookie);
|
|
|
+ public PaymentLinkResultsVo getPaymentLink(PaymentLinkVo vo) {
|
|
|
+ AttributionInformationVo attr = vo.getOrder().getAttributionInformationVo();
|
|
|
+ doLoginCookie(attr);
|
|
|
+ HtCrawlerOrder order = orderService.findByOrdersNo(vo.getOrder().getOrdersNo());
|
|
|
+ HtCrawlerConfigureParameters params = ConfigureParametersConversion.conversionEntity(
|
|
|
+ HtCrawlerConfigureParameters.class, attr.getConfigInfo());
|
|
|
+ HtCrawlerPaymentLinkResponse pl = queryPaymentLink(order, params, vo);
|
|
|
+ log.info("paymentLinkResponse: {}", JSONObject.toJSONString(pl));
|
|
|
+ return new PaymentLinkResultsVo(true, pl.getImg(), pl.getErrorInfo());
|
|
|
+ }
|
|
|
+
|
|
|
+ private HtCrawlerPaymentLinkResponse queryPaymentLink(HtCrawlerOrder order, HtCrawlerConfigureParameters params, PaymentLinkVo vo) {
|
|
|
+ MultiValueMap<String, String> qp = new LinkedMultiValueMap<>();
|
|
|
+ qp.add("cmd", "queryPaymentList");
|
|
|
+ qp.add("paytype", "jianfei");
|
|
|
+ qp.add("Single_system", "10000");
|
|
|
+ qp.add("checkStatus", "1");
|
|
|
+ qp.add("quotationno", order.getQuotationRelaNo());
|
|
|
+ String body = get(BASE_URL + "/htcsp/PaymentAction.do", buildPaymentListHeaders(req.getCookie()), qp);
|
|
|
+ log.info("queryPaymentList response: {}", body);
|
|
|
+ return req.getPaymentLink(new HtCrawlerPaymentLinkRequest(params, vo, body), buildPaymentListHeaders(req.getCookie()));
|
|
|
+ }
|
|
|
+
|
|
|
+ // ====================== Cookie 检查 ======================
|
|
|
+ private void doLoginCookie(AttributionInformationVo attr) {
|
|
|
+ if (StringUtils.isBlank(req.getCookie())) {
|
|
|
+ Map<String, Object> m = login(buildLoginDTO(attr));
|
|
|
+ String cookie = (String) m.get("cookie");
|
|
|
+ req.getHeaders().remove(HtRequestConstant.COOKIE);
|
|
|
+ req.getHeaders().add(HtRequestConstant.COOKIE, cookie);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// ====================== 影像上传 ======================
|
|
|
-
|
|
|
@Override
|
|
|
- public void uploadImage(InsuranceUploadImageVo insuranceUploadImageVo) {
|
|
|
- OrderBase orderBase = insuranceUploadImageVo.getOrder();
|
|
|
- AttributionInformationVo attributionInformationVo = orderBase.getAttributionInformationVo();
|
|
|
- doLoginCookie(attributionInformationVo);
|
|
|
- HtCrawlerOrder order = htCrawlerOrderService.findByOrdersNo(orderBase.getOrdersNo());
|
|
|
-
|
|
|
- // 判断是否重复上传
|
|
|
- String uploaded = huaTaiCrawlerCacheComponent.getYingXiangUploaded();
|
|
|
- if (StringUtils.isNotBlank(uploaded) && uploaded.equals(order.getQuotationRelaNo())) {
|
|
|
- return;
|
|
|
- }
|
|
|
+ public void uploadImage(InsuranceUploadImageVo vo) {
|
|
|
+ OrderBase orderBase = vo.getOrder();
|
|
|
+ AttributionInformationVo attr = orderBase.getAttributionInformationVo();
|
|
|
+ doLoginCookie(attr);
|
|
|
+ HtCrawlerOrder order = orderService.findByOrdersNo(orderBase.getOrdersNo());
|
|
|
|
|
|
- HtCrawlerConfigureParameters parameters = ConfigureParametersConversion.conversionEntity(
|
|
|
- HtCrawlerConfigureParameters.class, attributionInformationVo.getConfigInfo());
|
|
|
- HttpHeaders headers = buildUploadHeaders(htCrawlerRequestComponent.getCookie());
|
|
|
+ String uploaded = cache.getYingXiangUploaded();
|
|
|
+ if (StringUtils.isNotBlank(uploaded) && uploaded.equals(order.getQuotationRelaNo())) return;
|
|
|
+
|
|
|
+ HtCrawlerConfigureParameters params = ConfigureParametersConversion.conversionEntity(
|
|
|
+ HtCrawlerConfigureParameters.class, attr.getConfigInfo());
|
|
|
String quotationRelaNo = order.getQuotationRelaNo();
|
|
|
|
|
|
- List<Map<String, String>> b64phoList = new ArrayList<>();
|
|
|
- for (InsuranceImageVo insuranceImageVo : insuranceUploadImageVo.getImageVoList()) {
|
|
|
- for (InsuranceImageVo.ImageDTO imageDTO : insuranceImageVo.getImageBase64List()) {
|
|
|
- b64phoList.add(Map.of("imageBase64", imageDTO.getImageBase64Str(), "imgType", insuranceImageVo.getImageCode()));
|
|
|
+ List<Map<String, String>> b64List = new ArrayList<>();
|
|
|
+ for (InsuranceImageVo img : vo.getImageVoList()) {
|
|
|
+ for (InsuranceImageVo.ImageDTO dto : img.getImageBase64List()) {
|
|
|
+ b64List.add(Map.of("imageBase64", dto.getImageBase64Str(), "imgType", img.getImageCode()));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- HtCrawlerGerUploadUrlRequest uploadUrlRequest = new HtCrawlerGerUploadUrlRequest(quotationRelaNo);
|
|
|
- HtCrawlerGerUploadUrlResponse uploadUrlResponse = htCrawlerRequestComponent.getUploadUrl(uploadUrlRequest, headers);
|
|
|
+ HtCrawlerGerUploadUrlResponse up = req.getUploadUrl(new HtCrawlerGerUploadUrlRequest(quotationRelaNo), buildUploadHeaders(req.getCookie()));
|
|
|
String token = "";
|
|
|
- Map<String, Object> updataInfo = new LinkedHashMap<>();
|
|
|
-
|
|
|
- if (HtRequestConstant.GET_UPLOAD_URL_SUCCESS.equals(uploadUrlResponse.getFlag())) {
|
|
|
- token = uploadUrlResponse.getUrl().substring(uploadUrlResponse.getUrl().lastIndexOf("=") + 1);
|
|
|
- updataInfo = fetchUploadInitParam(token);
|
|
|
+ Map<String, Object> updata = new LinkedHashMap<>();
|
|
|
+ if (HtRequestConstant.GET_UPLOAD_URL_SUCCESS.equals(up.getFlag())) {
|
|
|
+ token = up.getUrl().substring(up.getUrl().lastIndexOf("=") + 1);
|
|
|
+ updata = fetchUploadInitParam(token);
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
- new UploadUtil().upLoad(quotationRelaNo, b64phoList, parseToMap(htCrawlerRequestComponent.getGsInfo()),
|
|
|
- attributionInformationVo.getUsername(), parameters.getComCode(),
|
|
|
- convertCookieToMap(htCrawlerRequestComponent.getCookie()),
|
|
|
- quotationRelaNo + "_", token, updataInfo);
|
|
|
- huaTaiCrawlerCacheComponent.cacheYingXiangUploaded(quotationRelaNo);
|
|
|
- } catch (Exception e) {
|
|
|
- throw new RuntimeException(e);
|
|
|
- }
|
|
|
+ new UploadUtil().upLoad(quotationRelaNo, b64List, parseToMap(req.getGsInfo()),
|
|
|
+ attr.getUsername(), params.getComCode(), convertCookieToMap(req.getCookie()),
|
|
|
+ quotationRelaNo + "_", token, updata);
|
|
|
+ cache.cacheYingXiangUploaded(quotationRelaNo);
|
|
|
+ } catch (Exception e) { throw new RuntimeException(e); }
|
|
|
}
|
|
|
|
|
|
private Map fetchUploadInitParam(String token) {
|
|
|
- HttpHeaders imageHeaders = new HttpHeaders();
|
|
|
- imageHeaders.set(HtRequestConstant.COOKIE, htCrawlerRequestComponent.getCookie());
|
|
|
- imageHeaders.set("Accept", "application/json, text/plain, */*");
|
|
|
- imageHeaders.set("Referer", "https://img-web.pc.ehuatai.com/app/upload.img?token=" + token);
|
|
|
- imageHeaders.set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36");
|
|
|
-
|
|
|
+ HttpHeaders h = new HttpHeaders();
|
|
|
+ h.set(HtRequestConstant.COOKIE, req.getCookie());
|
|
|
+ h.set("Accept", "application/json, text/plain, */*");
|
|
|
+ h.set("Referer", "https://img-web.pc.ehuatai.com/app/upload.img?token=" + token);
|
|
|
+ h.set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36");
|
|
|
String url = "https://img-web.pc.ehuatai.com/app/ImgManager/initParam.cdo";
|
|
|
- UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
|
|
|
- .queryParam("t", String.valueOf(System.currentTimeMillis()))
|
|
|
- .queryParam("token", token);
|
|
|
-
|
|
|
- return getRestTemplate().exchange(
|
|
|
- builder.toUriString(),
|
|
|
- HttpMethod.GET,
|
|
|
- new HttpEntity<>(imageHeaders),
|
|
|
- Map.class
|
|
|
- ).getBody();
|
|
|
+ String s = get(url + "?t=" + System.currentTimeMillis() + "&token=" + token, h, null);
|
|
|
+ Map<String, Object> map = null;
|
|
|
+ try {
|
|
|
+ map = new ObjectMapper().readValue(s, Map.class);
|
|
|
+ } catch (JsonProcessingException e) {
|
|
|
+ log.error("json parse error: {}", e.getMessage());
|
|
|
+ }
|
|
|
+ return map;
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public void queryClauseData(ClauseDataVo clauseDataVo) {
|
|
|
- // 空实现
|
|
|
- }
|
|
|
+ @Override public void queryClauseData(ClauseDataVo vo) { }
|
|
|
|
|
|
// ====================== 下载保单 ======================
|
|
|
-
|
|
|
@Override
|
|
|
- public DownloadPolicyResultVo downloadPolicy(DownloadPolicyVo downloadPolicyVo) {
|
|
|
- AttributionInformationVo attributionInformationVo = downloadPolicyVo.getOrder().getAttributionInformationVo();
|
|
|
- doLoginCookie(attributionInformationVo);
|
|
|
- String productId = downloadPolicyVo.getOrder().getProductId();
|
|
|
- String companyOrderNo = downloadPolicyVo.getOrder().getCompanyOrderNo();
|
|
|
-
|
|
|
- if (ProductsType.PT_0330.getCode().equals(productId)) {
|
|
|
- return downloadJqPolicy(companyOrderNo);
|
|
|
+ public DownloadPolicyResultVo downloadPolicy(DownloadPolicyVo vo) {
|
|
|
+ AttributionInformationVo attr = vo.getOrder().getAttributionInformationVo();
|
|
|
+ doLoginCookie(attr);
|
|
|
+ String productId = vo.getOrder().getProductId();
|
|
|
+ String companyOrderNo = vo.getOrder().getCompanyOrderNo();
|
|
|
+ return ProductsType.PT_0330.getCode().equals(productId)
|
|
|
+ ? downloadPolicy(companyOrderNo, true) : downloadPolicy(companyOrderNo, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ private DownloadPolicyResultVo downloadPolicy(String no, boolean jq) {
|
|
|
+ MultiValueMap<String, String> fd = new LinkedMultiValueMap<>();
|
|
|
+ fd.add("businessno", no);
|
|
|
+ fd.add("riskcode", jq ? "1002" : "1251");
|
|
|
+ fd.add("isbzdownload", "0");
|
|
|
+ fd.add("biztype", "P");
|
|
|
+ fd.add("elecProposalNoticeFlag", "");
|
|
|
+ fd.add("eleSymbolDownload", "1");
|
|
|
+ fd.add("tmpbiztype", "P");
|
|
|
+ fd.add("ownPrintElectronicFlag", "0");
|
|
|
+ fd.add("isbzdown", "1");
|
|
|
+ String body = post(BASE_URL + "/htcsp/DocumentPrintAction.do?cmd=electronicPolicyEndorseDownload",
|
|
|
+ buildDocumentHeaders(req.getCookie()), fd);
|
|
|
+ HtCrawlerDownloadPolicyResponse res = JSONObject.parseObject(body, HtCrawlerDownloadPolicyResponse.class);
|
|
|
+ DownloadPolicyResultVo r = new DownloadPolicyResultVo();
|
|
|
+ for (var ftp : res.getFtpdownloadJson()) {
|
|
|
+ if (jq) { r.setJqUrl(ftp.getDownurl()); r.setJqFlagUrl(ftp.getBzdownurl()); }
|
|
|
+ else { r.setSyUrl(ftp.getDownurl()); }
|
|
|
+ log.info("下载{}保单地址:{}", jq ? "交强" : "商业", ftp.getDownurl());
|
|
|
}
|
|
|
- return downloadSyPolicy(companyOrderNo);
|
|
|
- }
|
|
|
-
|
|
|
- private DownloadPolicyResultVo downloadJqPolicy(String companyOrderNo) {
|
|
|
- HttpHeaders headers = buildDocumentHeaders(htCrawlerRequestComponent.getCookie());
|
|
|
- MultiValueMap<String, String> formData = buildPolicyFormData(companyOrderNo, "1002");
|
|
|
- return executePolicyDownload(headers, formData, true);
|
|
|
- }
|
|
|
-
|
|
|
- private DownloadPolicyResultVo downloadSyPolicy(String companyOrderNo) {
|
|
|
- HttpHeaders headers = buildDocumentHeaders(htCrawlerRequestComponent.getCookie());
|
|
|
- MultiValueMap<String, String> formData = buildPolicyFormData(companyOrderNo, "1251");
|
|
|
- formData.add("elecProposalNoticeFlag", "");
|
|
|
- return executePolicyDownload(headers, formData, false);
|
|
|
- }
|
|
|
-
|
|
|
- private MultiValueMap<String, String> buildPolicyFormData(String companyOrderNo, String riskCode) {
|
|
|
- MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
|
|
|
- formData.add("businessno", companyOrderNo);
|
|
|
- formData.add("riskcode", riskCode);
|
|
|
- formData.add("isbzdownload", "0");
|
|
|
- formData.add("biztype", "P");
|
|
|
- formData.add("eleSymbolDownload", "1");
|
|
|
- formData.add("tmpbiztype", "P");
|
|
|
- formData.add("ownPrintElectronicFlag", "0");
|
|
|
- formData.add("isbzdown", "1");
|
|
|
- return formData;
|
|
|
- }
|
|
|
-
|
|
|
- private DownloadPolicyResultVo executePolicyDownload(HttpHeaders headers, MultiValueMap<String, String> formData, boolean isJq) {
|
|
|
- String url = BASE_URL + "/htcsp/DocumentPrintAction.do?cmd=electronicPolicyEndorseDownload";
|
|
|
- HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(formData, headers);
|
|
|
- ResponseEntity<String> response = getRestTemplate().exchange(url, HttpMethod.POST, request, String.class);
|
|
|
- String result = response.getBody();
|
|
|
- HtCrawlerDownloadPolicyResponse policyResponse = JSONObject.parseObject(result, HtCrawlerDownloadPolicyResponse.class);
|
|
|
-
|
|
|
- DownloadPolicyResultVo downloadPolicyResultVo = new DownloadPolicyResultVo();
|
|
|
- for (HtCrawlerDownloadPolicyResponse.FtpdownloadJson ftpdownloadJson : policyResponse.getFtpdownloadJson()) {
|
|
|
- if (isJq) {
|
|
|
- log.info("下载交强保单地址:{}", ftpdownloadJson.getDownurl());
|
|
|
- downloadPolicyResultVo.setJqUrl(ftpdownloadJson.getDownurl());
|
|
|
- downloadPolicyResultVo.setJqFlagUrl(ftpdownloadJson.getBzdownurl());
|
|
|
- } else {
|
|
|
- log.info("下载商业保单地址:{}", ftpdownloadJson.getDownurl());
|
|
|
- downloadPolicyResultVo.setSyUrl(ftpdownloadJson.getDownurl());
|
|
|
- }
|
|
|
- }
|
|
|
- return downloadPolicyResultVo;
|
|
|
+ return r;
|
|
|
}
|
|
|
|
|
|
// ====================== 查询订单状态 ======================
|
|
|
-
|
|
|
@Override
|
|
|
- public OrderStatusResultVo queryOrderState(OrderStatusVo orderStatusVo) {
|
|
|
- AttributionInformationVo attributionInformationVo = orderStatusVo.getOrder().getAttributionInformationVo();
|
|
|
- HtCrawlerConfigureParameters parameters = ConfigureParametersConversion.conversionEntity(
|
|
|
- HtCrawlerConfigureParameters.class, attributionInformationVo.getConfigInfo());
|
|
|
- HttpHeaders headers = htCrawlerRequestComponent.getHeaders();
|
|
|
-
|
|
|
- HtCrawlerOrder order = htCrawlerOrderService.findByOrdersNo(orderStatusVo.getOrder().getOrdersNo());
|
|
|
- String quotationRelaNo = order.getQuotationRelaNo();
|
|
|
-
|
|
|
- HtCrawlerOrderStateRequest stateRequest = new HtCrawlerOrderStateRequest(parameters, quotationRelaNo);
|
|
|
- String html = htCrawlerRequestComponent.queryOrderStatus(stateRequest, headers);
|
|
|
-
|
|
|
- Document document = Jsoup.parse(html);
|
|
|
- Elements trElement = document.select("table[id='table']").select("tbody").select("tr");
|
|
|
- Elements tdElements = trElement.select("td");
|
|
|
-
|
|
|
- // TODO: 完善字段映射并返回非空结果
|
|
|
- tdElements.get(1).firstElementChild().text(); // 客户名称
|
|
|
- tdElements.get(2).firstElementChild().text(); // 保险起保日期
|
|
|
- tdElements.get(3).firstElementChild().text(); // 车牌号
|
|
|
- tdElements.get(4).firstElementChild().text(); // 报价单创建日期
|
|
|
- tdElements.get(7).firstElementChild().text(); // 订单状态
|
|
|
+ public OrderStatusResultVo queryOrderState(OrderStatusVo vo) {
|
|
|
+ AttributionInformationVo attr = vo.getOrder().getAttributionInformationVo();
|
|
|
+ HtCrawlerConfigureParameters params = ConfigureParametersConversion.conversionEntity(
|
|
|
+ HtCrawlerConfigureParameters.class, attr.getConfigInfo());
|
|
|
+ HtCrawlerOrder order = orderService.findByOrdersNo(vo.getOrder().getOrdersNo());
|
|
|
+ String html = req.queryOrderStatus(new HtCrawlerOrderStateRequest(params, order.getQuotationRelaNo()), req.getHeaders());
|
|
|
+ Document doc = Jsoup.parse(html);
|
|
|
+ Elements tds = doc.select("table[id='table'] tbody tr td");
|
|
|
+ // TODO: 完善字段映射
|
|
|
+ tds.get(1).firstElementChild().text(); // 客户名称
|
|
|
+ tds.get(2).firstElementChild().text(); // 保险起保日期
|
|
|
+ tds.get(3).firstElementChild().text(); // 车牌号
|
|
|
+ tds.get(4).firstElementChild().text(); // 报价单创建日期
|
|
|
+ tds.get(7).firstElementChild().text(); // 订单状态
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- // ====================== Headers 工厂方法 ======================
|
|
|
+ // ====================== Headers 统一构建 ======================
|
|
|
+ private HttpHeaders header(Consumer<HttpHeaders> customizer) {
|
|
|
+ HttpHeaders h = new HttpHeaders();
|
|
|
+ h.add("User-Agent", UA);
|
|
|
+ h.add("Accept-Language", "zh-CN,zh;q=0.9");
|
|
|
+ h.add("Connection", "keep-alive");
|
|
|
+ customizer.accept(h);
|
|
|
+ return h;
|
|
|
+ }
|
|
|
|
|
|
- private HttpHeaders buildHtmlHeadersWithCookie(String cookie) {
|
|
|
- HttpHeaders headers = new HttpHeaders();
|
|
|
- headers.set("User-Agent", USER_AGENT);
|
|
|
- headers.set("Accept", ACCEPT_HTML);
|
|
|
- headers.set("Accept-Language", "zh-CN,zh;q=0.9");
|
|
|
- headers.set("Cache-Control", "no-cache");
|
|
|
- headers.set("Connection", "keep-alive");
|
|
|
- headers.set("Pragma", "no-cache");
|
|
|
- headers.set("Upgrade-Insecure-Requests", "1");
|
|
|
- headers.set("Cookie", cookie);
|
|
|
- return headers;
|
|
|
+ private HttpHeaders buildHtmlHeaders(String cookie) {
|
|
|
+ return header(h -> {
|
|
|
+ h.set("Accept", ACCEPT_HTML);
|
|
|
+ h.set("Cache-Control", "no-cache");
|
|
|
+ h.set("Pragma", "no-cache");
|
|
|
+ h.set("Upgrade-Insecure-Requests", "1");
|
|
|
+ h.set("Cookie", cookie);
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
- private HttpHeaders buildJsonHeadersWithCookie(String cookie) {
|
|
|
- HttpHeaders headers = new HttpHeaders();
|
|
|
- headers.set("Accept", ACCEPT_JSON);
|
|
|
- headers.set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
|
|
|
- headers.set("Connection", "keep-alive");
|
|
|
- headers.set("Content-Type", CONTENT_TYPE_FORM);
|
|
|
- headers.set("Origin", ORIGIN);
|
|
|
- headers.set("Referer", REFERER_START_PROCESS);
|
|
|
- headers.set("User-Agent", USER_AGENT);
|
|
|
- headers.set("X-Requested-With", X_REQUESTED_WITH);
|
|
|
- headers.set("Cookie", cookie);
|
|
|
- return headers;
|
|
|
+ private HttpHeaders buildJsonHeaders(String cookie) {
|
|
|
+ return header(h -> {
|
|
|
+ h.set("Accept", ACCEPT_JSON);
|
|
|
+ h.set("Content-Type", CONTENT_TYPE_FORM);
|
|
|
+ h.set("Origin", ORIGIN);
|
|
|
+ h.set("Referer", ORIGIN + "/htcsp/VehicleInfoEntryAction.do?cmd=startProcess");
|
|
|
+ h.set("X-Requested-With", XHR);
|
|
|
+ h.set("Cookie", cookie);
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
private HttpHeaders buildQuoteStep1Headers(String cookie) {
|
|
|
- HttpHeaders headers = new HttpHeaders();
|
|
|
- headers.add(HtRequestConstant.COOKIE, cookie);
|
|
|
- headers.add("Accept", ACCEPT_HTML);
|
|
|
- headers.add("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
|
|
|
- headers.add("Cache-Control", "no-cache");
|
|
|
- headers.add("Connection", "keep-alive");
|
|
|
- headers.add("Content-Type", CONTENT_TYPE_FORM_SIMPLE);
|
|
|
- headers.add("Origin", ORIGIN);
|
|
|
- headers.add("Pragma", "no-cache");
|
|
|
- headers.add("Referer", REFERER_START_PROCESS);
|
|
|
- headers.add("Upgrade-Insecure-Requests", "1");
|
|
|
- headers.add("User-Agent", USER_AGENT);
|
|
|
- return headers;
|
|
|
+ return header(h -> {
|
|
|
+ h.add(HtRequestConstant.COOKIE, cookie);
|
|
|
+ h.add("Accept", ACCEPT_HTML);
|
|
|
+ h.add("Cache-Control", "no-cache");
|
|
|
+ h.add("Content-Type", "application/x-www-form-urlencoded");
|
|
|
+ h.add("Origin", ORIGIN);
|
|
|
+ h.add("Pragma", "no-cache");
|
|
|
+ h.add("Referer", ORIGIN + "/htcsp/VehicleInfoEntryAction.do?cmd=startProcess");
|
|
|
+ h.add("Upgrade-Insecure-Requests", "1");
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
private HttpHeaders buildQuoteStep2Headers(String cookie) {
|
|
|
- HttpHeaders headers = new HttpHeaders();
|
|
|
- headers.add(HtRequestConstant.COOKIE, cookie);
|
|
|
- headers.add("Accept", ACCEPT_ALL);
|
|
|
- headers.add("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
|
|
|
- headers.add("Cache-Control", "no-cache");
|
|
|
- headers.add("Connection", "keep-alive");
|
|
|
- headers.add("Content-Type", CONTENT_TYPE_FORM);
|
|
|
- headers.add("Origin", ORIGIN);
|
|
|
- headers.add("Pragma", "no-cache");
|
|
|
- headers.add("Referer", REFERER_SAVE_ONE_STEP);
|
|
|
- headers.add("User-Agent", USER_AGENT);
|
|
|
- headers.add("X-Requested-With", X_REQUESTED_WITH);
|
|
|
- return headers;
|
|
|
+ return header(h -> {
|
|
|
+ h.add(HtRequestConstant.COOKIE, cookie);
|
|
|
+ h.add("Accept", "*/*");
|
|
|
+ h.add("Cache-Control", "no-cache");
|
|
|
+ h.add("Content-Type", CONTENT_TYPE_FORM);
|
|
|
+ h.add("Origin", ORIGIN);
|
|
|
+ h.add("Pragma", "no-cache");
|
|
|
+ h.add("Referer", ORIGIN + "/htcsp/VehicleInfoEntryAction.do?cmd=saveOneStept");
|
|
|
+ h.add("X-Requested-With", XHR);
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
private HttpHeaders buildPaymentListHeaders(String cookie) {
|
|
|
- HttpHeaders headers = new HttpHeaders();
|
|
|
- headers.add(HtRequestConstant.COOKIE, cookie);
|
|
|
- headers.add("Accept", ACCEPT_HTML);
|
|
|
- headers.add("Accept-Language", "zh-CN,zh;q=0.9");
|
|
|
- headers.add("Connection", "keep-alive");
|
|
|
- headers.add("Referer", REFERER_QUOTATION_LIST);
|
|
|
- headers.add("Upgrade-Insecure-Requests", "1");
|
|
|
- headers.add("User-Agent", USER_AGENT);
|
|
|
- return headers;
|
|
|
+ return header(h -> {
|
|
|
+ h.add(HtRequestConstant.COOKIE, cookie);
|
|
|
+ h.add("Accept", ACCEPT_HTML);
|
|
|
+ h.add("Referer", ORIGIN + "/htcsp/QuotationQueryAction.do?cmd=quotationListAll");
|
|
|
+ h.add("Upgrade-Insecure-Requests", "1");
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
private HttpHeaders buildDocumentHeaders(String cookie) {
|
|
|
- HttpHeaders headers = new HttpHeaders();
|
|
|
- headers.set(HtRequestConstant.COOKIE, cookie);
|
|
|
- headers.set("Accept", ACCEPT_JSON);
|
|
|
- headers.set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
|
|
|
- headers.set("Cache-Control", "no-cache");
|
|
|
- headers.set("Connection", "keep-alive");
|
|
|
- headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
|
|
- headers.set("Origin", ORIGIN);
|
|
|
- headers.set("Pragma", "no-cache");
|
|
|
- headers.set("Referer", REFERER_DOCUMENT_PRINT);
|
|
|
- headers.set("User-Agent", USER_AGENT);
|
|
|
- headers.set("X-Requested-With", X_REQUESTED_WITH);
|
|
|
- return headers;
|
|
|
+ return header(h -> {
|
|
|
+ h.set(HtRequestConstant.COOKIE, cookie);
|
|
|
+ h.set("Accept", ACCEPT_JSON);
|
|
|
+ h.set("Cache-Control", "no-cache");
|
|
|
+ h.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
|
|
+ h.set("Origin", ORIGIN);
|
|
|
+ h.set("Pragma", "no-cache");
|
|
|
+ h.set("Referer", ORIGIN + "/htcsp/DocumentPrintAction.do?cmd=queryDocumentPrintList");
|
|
|
+ h.set("X-Requested-With", XHR);
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
private HttpHeaders buildUploadHeaders(String cookie) {
|
|
|
- HttpHeaders headers = new HttpHeaders();
|
|
|
- headers.set(HtRequestConstant.COOKIE, cookie);
|
|
|
- headers.set("Accept", ACCEPT_ALL);
|
|
|
- headers.set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
|
|
|
- headers.set("Cache-Control", "no-cache");
|
|
|
- headers.set("Connection", "keep-alive");
|
|
|
- headers.set("Content-Type", CONTENT_TYPE_FORM);
|
|
|
- headers.set("Origin", ORIGIN);
|
|
|
- headers.set("Pragma", "no-cache");
|
|
|
- headers.set("Referer", REFERER_CHECK_INS);
|
|
|
- headers.set("User-Agent", USER_AGENT);
|
|
|
- headers.set("X-Requested-With", X_REQUESTED_WITH);
|
|
|
- return headers;
|
|
|
- }
|
|
|
-
|
|
|
- private HttpHeaders buildSpecialHeaders(String cookie) {
|
|
|
- HttpHeaders headers = new HttpHeaders();
|
|
|
- headers.set("Accept", ACCEPT_HTML);
|
|
|
- headers.set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
|
|
|
- headers.set("Cache-Control", "no-cache");
|
|
|
- headers.set("Connection", "keep-alive");
|
|
|
- headers.set("Pragma", "no-cache");
|
|
|
- headers.set("Referer", ORIGIN + "/htcsp/ShakeHandsAction.do?cmd=contentInit");
|
|
|
- headers.set("Upgrade-Insecure-Requests", "1");
|
|
|
- headers.set("User-Agent", USER_AGENT);
|
|
|
- headers.set("Cookie", cookie);
|
|
|
- return headers;
|
|
|
- }
|
|
|
-
|
|
|
- private HttpHeaders buildSpecialHeaders2(String cookie) {
|
|
|
- HttpHeaders headers = new HttpHeaders();
|
|
|
- headers.set("Accept", ACCEPT_HTML);
|
|
|
- headers.set("Accept-Language", "zh-CN,zh;q=0.8");
|
|
|
- headers.set("Cache-Control", "no-cache");
|
|
|
- headers.set("Connection", "keep-alive");
|
|
|
- headers.set("Pragma", "no-cache");
|
|
|
- headers.set("Referer", ORIGIN + "/htcsp/ShakeHandsAction.do?cmd=contentInit");
|
|
|
- headers.set("Upgrade-Insecure-Requests", "1");
|
|
|
- headers.set("User-Agent", USER_AGENT);
|
|
|
- headers.set("Cookie", cookie);
|
|
|
- return headers;
|
|
|
+ return header(h -> {
|
|
|
+ h.set(HtRequestConstant.COOKIE, cookie);
|
|
|
+ h.set("Accept", "*/*");
|
|
|
+ h.set("Cache-Control", "no-cache");
|
|
|
+ h.set("Content-Type", CONTENT_TYPE_FORM);
|
|
|
+ h.set("Origin", ORIGIN);
|
|
|
+ h.set("Pragma", "no-cache");
|
|
|
+ h.set("Referer", ORIGIN + "/htcsp/checkInsAction.do?cmd=welcome&recommendNo=&checkedThreeWriteFlagRecommend=Y");
|
|
|
+ h.set("X-Requested-With", XHR);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private HttpHeaders buildSpecialHeaders(String cookie, boolean first) {
|
|
|
+ return header(h -> {
|
|
|
+ h.set("Accept", ACCEPT_HTML);
|
|
|
+ h.set("Cache-Control", "no-cache");
|
|
|
+ h.set("Pragma", "no-cache");
|
|
|
+ h.set("Referer", ORIGIN + "/htcsp/ShakeHandsAction.do?cmd=contentInit");
|
|
|
+ h.set("Upgrade-Insecure-Requests", "1");
|
|
|
+ h.set("Cookie", cookie);
|
|
|
+ if (!first) h.set("Accept-Language", "zh-CN,zh;q=0.8");
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
private HttpHeaders buildCarQueryHeaders(String cookie) {
|
|
|
- HttpHeaders headers = new HttpHeaders();
|
|
|
- headers.add(HtRequestConstant.COOKIE, cookie);
|
|
|
- headers.add("Accept", ACCEPT_JSON);
|
|
|
- headers.add("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8");
|
|
|
- headers.add("Cache-Control", "no-cache");
|
|
|
- headers.add("Connection", "keep-alive");
|
|
|
- headers.add("Content-Type", CONTENT_TYPE_FORM);
|
|
|
- headers.add("Origin", ORIGIN);
|
|
|
- headers.add("Pragma", "no-cache");
|
|
|
- headers.add("Referer", REFERER_START_PROCESS);
|
|
|
- headers.add("User-Agent", USER_AGENT);
|
|
|
- headers.add("X-Requested-With", X_REQUESTED_WITH);
|
|
|
- return headers;
|
|
|
+ return header(h -> {
|
|
|
+ h.add(HtRequestConstant.COOKIE, cookie);
|
|
|
+ h.add("Accept", ACCEPT_JSON);
|
|
|
+ h.add("Cache-Control", "no-cache");
|
|
|
+ h.add("Content-Type", CONTENT_TYPE_FORM);
|
|
|
+ h.add("Origin", ORIGIN);
|
|
|
+ h.add("Pragma", "no-cache");
|
|
|
+ h.add("Referer", ORIGIN + "/htcsp/VehicleInfoEntryAction.do?cmd=startProcess");
|
|
|
+ h.add("X-Requested-With", XHR);
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
private HttpHeaders buildCarModelCodexhHeaders(String cookie) {
|
|
|
- HttpHeaders headers = new HttpHeaders();
|
|
|
- headers.add("Accept", ACCEPT_JSON);
|
|
|
- headers.add("Content-Type", CONTENT_TYPE_FORM);
|
|
|
- headers.add("User-Agent", USER_AGENT);
|
|
|
- headers.add("X-Requested-With", X_REQUESTED_WITH);
|
|
|
- headers.add(HtRequestConstant.COOKIE, cookie);
|
|
|
- return headers;
|
|
|
- }
|
|
|
-
|
|
|
- private HttpHeaders buildManualUnderwritingHeaders() {
|
|
|
- HttpHeaders headers = new HttpHeaders();
|
|
|
- headers.add(HtRequestConstant.COOKIE, htCrawlerRequestComponent.getCookie());
|
|
|
- headers.add("Accept", ACCEPT_JSON);
|
|
|
- headers.add("Accept-Language", "zh-CN,zh;q=0.9");
|
|
|
- headers.add("Connection", "keep-alive");
|
|
|
- headers.add("Content-Type", CONTENT_TYPE_FORM);
|
|
|
- headers.add("User-Agent", USER_AGENT);
|
|
|
- headers.add("X-Requested-With", X_REQUESTED_WITH);
|
|
|
- return headers;
|
|
|
+ return header(h -> {
|
|
|
+ h.add("Accept", ACCEPT_JSON);
|
|
|
+ h.add("Content-Type", CONTENT_TYPE_FORM);
|
|
|
+ h.add("X-Requested-With", XHR);
|
|
|
+ h.add(HtRequestConstant.COOKIE, cookie);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private HttpHeaders buildManualUwHeaders() {
|
|
|
+ return header(h -> {
|
|
|
+ h.add(HtRequestConstant.COOKIE, req.getCookie());
|
|
|
+ h.add("Accept", ACCEPT_JSON);
|
|
|
+ h.add("Content-Type", CONTENT_TYPE_FORM);
|
|
|
+ h.add("X-Requested-With", XHR);
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
private HttpHeaders buildPaymentLinkHeaders() {
|
|
|
- HttpHeaders headers = new HttpHeaders();
|
|
|
- headers.add(HtRequestConstant.COOKIE, htCrawlerRequestComponent.getCookie());
|
|
|
- headers.add("Accept", "text/html, */*; q=0.01");
|
|
|
- headers.add("Accept-Language", "zh-CN,zh;q=0.9");
|
|
|
- headers.add("Connection", "keep-alive");
|
|
|
- headers.add("Content-Type", CONTENT_TYPE_FORM);
|
|
|
- headers.add("Referer", REFERER_QUOTATION_LIST);
|
|
|
- headers.add("Upgrade-Insecure-Requests", "1");
|
|
|
- headers.add("User-Agent", USER_AGENT);
|
|
|
- return headers;
|
|
|
+ return header(h -> {
|
|
|
+ h.add(HtRequestConstant.COOKIE, req.getCookie());
|
|
|
+ h.add("Accept", "text/html, */*; q=0.01");
|
|
|
+ h.add("Content-Type", CONTENT_TYPE_FORM);
|
|
|
+ h.add("Referer", ORIGIN + "/htcsp/QuotationQueryAction.do?cmd=quotationListAll");
|
|
|
+ h.add("Upgrade-Insecure-Requests", "1");
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
- // ====================== 工具方法 ======================
|
|
|
+ private HttpHeaders buildNoCarPremiumHeaders(String cookie) {
|
|
|
+ return header(h -> {
|
|
|
+ h.add(HtRequestConstant.COOKIE, cookie);
|
|
|
+ h.add("Accept", "*/*");
|
|
|
+ h.add("Content-Type", CONTENT_TYPE_FORM);
|
|
|
+ h.add("Origin", ORIGIN);
|
|
|
+ h.add("Referer", ORIGIN + "/htcsp/VehicleInfoEntryAction.do?cmd=saveOneStept");
|
|
|
+ h.add("X-Requested-With", XHR);
|
|
|
+ });
|
|
|
+ }
|
|
|
|
|
|
- private static Map<String, Object> parseToMap(String input) {
|
|
|
- Map<String, Object> map = new HashMap<>();
|
|
|
- if (StringUtils.isBlank(input)) {
|
|
|
- return map;
|
|
|
- }
|
|
|
- String content = input.trim();
|
|
|
- if (content.startsWith("{")) {
|
|
|
- content = content.substring(1);
|
|
|
- }
|
|
|
- if (content.endsWith("}")) {
|
|
|
- content = content.substring(0, content.length() - 1);
|
|
|
- }
|
|
|
+ // ====================== HTTP 通用工具 ======================
|
|
|
+ private String get(String url, HttpHeaders headers, MultiValueMap<String, String> params) {
|
|
|
+ UriComponentsBuilder b = UriComponentsBuilder.fromHttpUrl(url);
|
|
|
+ if (params != null) b.queryParams(params);
|
|
|
+ return RT.exchange(b.toUriString(), HttpMethod.GET, new HttpEntity<>(headers), String.class).getBody();
|
|
|
+ }
|
|
|
|
|
|
- String[] pairs = content.split(",\\s*");
|
|
|
- for (String pair : pairs) {
|
|
|
- String[] keyValue = pair.split("=", 2);
|
|
|
- if (keyValue.length == 2) {
|
|
|
- map.put(keyValue[0].trim(), keyValue[1].trim());
|
|
|
- }
|
|
|
- }
|
|
|
- return map;
|
|
|
+ private String post(String url, HttpHeaders headers, MultiValueMap<String, String> data) {
|
|
|
+ return RT.postForEntity(url, new HttpEntity<>(data, headers), String.class).getBody();
|
|
|
}
|
|
|
|
|
|
- private static void fillVehicleTypeCodes(CarInfoVo carInfoVo, Map<String, Object> data) {
|
|
|
- String useCode = carInfoVo.getVehicleUseCode();
|
|
|
- String kindCode = carInfoVo.getCarKindCode();
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ private Map<String, Object> exchangeForm(String url, Map<String, String> queryParams,
|
|
|
+ MultiValueMap<String, String> data, HttpHeaders headers) throws JsonProcessingException {
|
|
|
+ UriComponentsBuilder b = UriComponentsBuilder.fromHttpUrl(url);
|
|
|
+ if (queryParams != null) queryParams.forEach(b::queryParam);
|
|
|
+ String body = RT.exchange(b.toUriString(), HttpMethod.POST, new HttpEntity<>(data, headers), String.class).getBody();
|
|
|
+ return MAPPER.readValue(body, Map.class);
|
|
|
+ }
|
|
|
|
|
|
- switch (useCode) {
|
|
|
- case "04" -> {
|
|
|
- data.put("motortypecode", "H0");
|
|
|
- data.put("motorusagetypecode", "9D");
|
|
|
- }
|
|
|
- case "05" -> {
|
|
|
- data.put("motortypecode", "A0");
|
|
|
- data.put("motorusagetypecode", "8A");
|
|
|
- }
|
|
|
+ // ====================== 工具方法 ======================
|
|
|
+ private static Map<String, Object> parseToMap(String input) {
|
|
|
+ Map<String, Object> m = new HashMap<>();
|
|
|
+ if (StringUtils.isBlank(input)) return m;
|
|
|
+ String c = input.trim();
|
|
|
+ if (c.startsWith("{")) c = c.substring(1);
|
|
|
+ if (c.endsWith("}")) c = c.substring(0, c.length() - 1);
|
|
|
+ for (String pair : c.split(",\\s*")) {
|
|
|
+ String[] kv = pair.split("=", 2);
|
|
|
+ if (kv.length == 2) m.put(kv[0].trim(), kv[1].trim());
|
|
|
+ }
|
|
|
+ return m;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void fillVehicleTypeCodes(CarInfoVo car, Map<String, Object> data) {
|
|
|
+ String use = car.getVehicleUseCode(), kind = car.getCarKindCode();
|
|
|
+ switch (use) {
|
|
|
+ case "04" -> data.putAll(Map.of("motortypecode", "H0", "motorusagetypecode", "9D"));
|
|
|
+ case "05" -> data.putAll(Map.of("motortypecode", "A0", "motorusagetypecode", "8A"));
|
|
|
case "06" -> {
|
|
|
- if ("A0".equals(kindCode)) {
|
|
|
- data.put("motortypecode", "A0");
|
|
|
- data.put("motorusagetypecode", "8C");
|
|
|
- } else if ("A1".equals(kindCode)) {
|
|
|
- data.put("motortypecode", "H0");
|
|
|
- data.put("motorusagetypecode", "8D");
|
|
|
- }
|
|
|
+ if ("A0".equals(kind)) data.putAll(Map.of("motortypecode", "A0", "motorusagetypecode", "8C"));
|
|
|
+ else if ("A1".equals(kind)) data.putAll(Map.of("motortypecode", "H0", "motorusagetypecode", "8D"));
|
|
|
}
|
|
|
case "07" -> {
|
|
|
- if ("A0".equals(kindCode)) {
|
|
|
- data.put("motortypecode", "A0");
|
|
|
- data.put("motorusagetypecode", "8B");
|
|
|
- } else if ("A1".equals(kindCode)) {
|
|
|
- data.put("motortypecode", "H0");
|
|
|
- data.put("motorusagetypecode", "8D");
|
|
|
- }
|
|
|
- }
|
|
|
- case "08" -> {
|
|
|
- data.put("motortypecode", "H0");
|
|
|
- data.put("motorusagetypecode", "8D");
|
|
|
+ if ("A0".equals(kind)) data.putAll(Map.of("motortypecode", "A0", "motorusagetypecode", "8B"));
|
|
|
+ else if ("A1".equals(kind)) data.putAll(Map.of("motortypecode", "H0", "motorusagetypecode", "8D"));
|
|
|
}
|
|
|
+ case "08" -> data.putAll(Map.of("motortypecode", "H0", "motorusagetypecode", "8D"));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public Map<String, Object> encrypt(Map<String, Object> x) throws Exception {
|
|
|
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
|
- StringBuilder keyBuilder = new StringBuilder();
|
|
|
- Random random = new Random();
|
|
|
- for (int i = 0; i < 16; i++) {
|
|
|
- keyBuilder.append(alphabet.charAt(random.nextInt(alphabet.length())));
|
|
|
- }
|
|
|
- String key = keyBuilder.toString();
|
|
|
-
|
|
|
- Map<String, Object> makeInputData = new HashMap<>();
|
|
|
- makeInputData.put("sourceCode", 8);
|
|
|
- makeInputData.put("accessToken", CryptoUtil.rsaEncrypt(key));
|
|
|
- makeInputData.put("data", CryptoUtil.aesEncrypt(OBJECT_MAPPER.writeValueAsString(x), key));
|
|
|
- makeInputData.put("insuredCode", "");
|
|
|
- return makeInputData;
|
|
|
+ StringBuilder kb = new StringBuilder();
|
|
|
+ Random r = new Random();
|
|
|
+ for (int i = 0; i < 16; i++) kb.append(alphabet.charAt(r.nextInt(alphabet.length())));
|
|
|
+ String key = kb.toString();
|
|
|
+ return Map.of("sourceCode", 8, "accessToken", CryptoUtil.rsaEncrypt(key),
|
|
|
+ "data", CryptoUtil.aesEncrypt(MAPPER.writeValueAsString(x), key), "insuredCode", "");
|
|
|
}
|
|
|
|
|
|
public Map<String, Object> decrypt(Map<String, Object> x) throws Exception {
|
|
|
- String accessToken = (String) x.get("accessToken");
|
|
|
- String data = (String) x.get("data");
|
|
|
- String aesKey = CryptoUtil.rsaDecrypt(accessToken);
|
|
|
- String decrypted = CryptoUtil.aesDecrypt(data, aesKey);
|
|
|
- return OBJECT_MAPPER.readValue(decrypted, HashMap.class);
|
|
|
- }
|
|
|
-
|
|
|
- public static Map<String, String> convertCookieToMap(String cookieStr) {
|
|
|
- Map<String, String> map = new HashMap<>();
|
|
|
- if (StringUtils.isBlank(cookieStr)) {
|
|
|
- return map;
|
|
|
- }
|
|
|
- String[] pairs = cookieStr.split(";");
|
|
|
- for (String pair : pairs) {
|
|
|
- pair = pair.trim();
|
|
|
- if (pair.isEmpty()) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- int index = pair.indexOf("=");
|
|
|
- if (index > 0) {
|
|
|
- map.put(pair.substring(0, index), pair.substring(index + 1));
|
|
|
- }
|
|
|
+ String aesKey = CryptoUtil.rsaDecrypt((String) x.get("accessToken"));
|
|
|
+ String decrypted = CryptoUtil.aesDecrypt((String) x.get("data"), aesKey);
|
|
|
+ return MAPPER.readValue(decrypted, HashMap.class);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Map<String, String> convertCookieToMap(String s) {
|
|
|
+ Map<String, String> m = new HashMap<>();
|
|
|
+ if (StringUtils.isBlank(s)) return m;
|
|
|
+ for (String p : s.split(";")) {
|
|
|
+ p = p.trim();
|
|
|
+ if (p.isEmpty()) continue;
|
|
|
+ int i = p.indexOf('=');
|
|
|
+ if (i > 0) m.put(p.substring(0, i), p.substring(i + 1));
|
|
|
}
|
|
|
- return map;
|
|
|
+ return m;
|
|
|
}
|
|
|
}
|